From 7d8e2d53f774b4747806bc859f22551e9d86bf30 Mon Sep 17 00:00:00 2001 From: Linus Svensson Date: Mon, 29 Aug 2016 18:29:07 +0200 Subject: [PATCH] daemon-conf: Add conf file parsing Support to parse configuration files. By default, the default conf file is parsed ({sysconfdir}/pinos/pinos.conf), but that can be changed with an environment variable (PINOS_CONFIG_FILE). The file can contain commands and assignments (no assignment supported this far). Support for command module-load is added. --- configure.ac | 16 +++ pinos/Makefile.am | 25 +++- pinos/daemon/daemon-config.c | 218 ++++++++++++++++++++++++++++++ pinos/daemon/daemon-config.h | 75 +++++++++++ pinos/daemon/main.c | 19 ++- pinos/daemon/pinos.conf.in | 1 + pinos/modules/gst/module.c | 4 +- pinos/modules/spa/module.c | 36 +++++ pinos/server/command.c | 251 +++++++++++++++++++++++++++++++++++ pinos/server/command.h | 69 ++++++++++ pinos/server/module.c | 8 +- pinos/server/module.h | 4 +- pinos/tests/test-client.c | 38 ------ spa/include/spa/node.h | 24 +++- 14 files changed, 729 insertions(+), 59 deletions(-) create mode 100644 pinos/daemon/daemon-config.c create mode 100644 pinos/daemon/daemon-config.h create mode 100644 pinos/daemon/pinos.conf.in create mode 100644 pinos/modules/spa/module.c create mode 100644 pinos/server/command.c create mode 100644 pinos/server/command.h diff --git a/configure.ac b/configure.ac index 279093f9c..1abd17da6 100644 --- a/configure.ac +++ b/configure.ac @@ -177,6 +177,12 @@ AS_IF([test "x$LIBLTDL" = "x"], [AC_MSG_ERROR([Unable to find libltdl version 2. Makes sure you have libtool 2.4 or later installed.])]) AC_SUBST([LIBLTDL]) + +#### Pinos runtime environment #### + +AC_SUBST(pinosconfdir, ["${sysconfdir}/pinos"]) +AX_DEFINE_DIR(PINOS_CONFIG_DIR, pinosconfdir, [Directory for configuration files]) + ################################### # External libraries # ################################### @@ -260,6 +266,14 @@ AC_ARG_ENABLE([module-gst], AM_CONDITIONAL([BUILD_MODULE_GST], [test "x$enable_module_gst" != "xno"]) AS_IF([test "x$enable_module_gst" != "xno"], ENABLE_MODULE_GST=yes, ENABLE_MODULE_GST=no) +#### module-spa (SPA module) #### +AC_ARG_ENABLE([module-spa], + AS_HELP_STRING([--disable-module-spa],[Disable building of SPA module])) + +AM_CONDITIONAL([BUILD_MODULE_SPA], [test "x$enable_module_spa" != "xno"]) +AS_IF([test "x$enable_module_spa" != "xno"], ENABLE_MODULE_SPA=yes, ENABLE_MODULE_SPA=no) + + #### Build and Install man pages #### AC_ARG_ENABLE([manpages], @@ -273,6 +287,7 @@ dnl keep this alphabetic per directory, please AC_CONFIG_FILES([ Makefile pinos/Makefile +pinos/daemon/pinos.conf man/Makefile man/pinos.1.xml man/pinos-monitor.1.xml @@ -292,6 +307,7 @@ Configuration Modules module-gst : ${ENABLE_MODULE_GST} + module-spa : ${ENABLE_MODULE_SPA} pinos configured. Type 'make' to build. " diff --git a/pinos/Makefile.am b/pinos/Makefile.am index 4d03a7b33..5c2e09352 100644 --- a/pinos/Makefile.am +++ b/pinos/Makefile.am @@ -36,7 +36,7 @@ AM_CPPFLAGS = \ -I$(top_builddir)/pinos/modules \ -DPINOS_SRCDIR=\"$(abs_srcdir)\" \ -DPINOS_BUILDDIR=\"$(abs_builddir)\" -AM_CFLAGS = $(GLIB_CFLAGS) $(GST_CFLAGS) +AM_CFLAGS = $(GLIB_CFLAGS) AM_CXXFLAGS = $(AM_CFLAGS) SERVER_CFLAGS = -D__INCLUDED_FROM_PINOS @@ -55,10 +55,14 @@ MODULE_LIBADD = $(AM_LIBADD) libpinoscore-@PINOS_MAJORMINOR@.la EXTRA_DIST = \ daemon/pinos-system.conf \ + daemon/pinos.conf.in \ daemon/pinos.desktop.in \ dbus/org.pinos.xml \ client/private.h +pinosconf_DATA = \ + daemon/pinos.conf + dbuspolicy_DATA = \ daemon/pinos-system.conf @@ -121,6 +125,7 @@ CLEANFILES = $(built_header_make) $(built_source_make) bin_PROGRAMS = pinos pinos_SOURCES = \ + daemon/daemon-config.h daemon/daemon-config.c \ daemon/main.c pinos_CFLAGS = $(AM_CFLAGS) @@ -205,14 +210,13 @@ lib_LTLIBRARIES += libpinoscore-@PINOS_MAJORMINOR@.la libpinoscore_@PINOS_MAJORMINOR@_la_SOURCES = \ server/client.c server/client.h \ server/client-node.c server/client-node.h \ + server/command.c server/command.h \ server/daemon.c server/daemon.h \ server/link.c server/link.h \ server/module.c server/module.h \ server/node.c server/node.h \ server/port.c server/port.h \ server/node-factory.c server/node-factory.h \ - modules/spa/spa-alsa-sink.c modules/spa/spa-alsa-sink.h \ - modules/spa/spa-v4l2-source.c modules/spa/spa-v4l2-source.h \ dbus/org-pinos.c dbus/org-pinos.h libpinoscore_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS) @@ -240,6 +244,21 @@ module_gst_la_LDFLAGS = $(MODULE_LDFLAGS) module_gst_la_LIBADD = $(MODULE_LIBADD) endif +if BUILD_MODULE_SPA +module_LTLIBRARIES += module-spa.la + +module_spa_la_SOURCES = \ + modules/spa/spa-alsa-sink.c \ + modules/spa/spa-v4l2-source.c \ + modules/spa/module.c +module_spa_la_CFLAGS = $(AM_CFLAGS) +module_spa_la_LDFLAGS = $(MODULE_LDFLAGS) +module_spa_la_LIBADD = $(MODULE_LIBADD) +endif + + + + ################################### # GStreamer Plugin # ################################### diff --git a/pinos/daemon/daemon-config.c b/pinos/daemon/daemon-config.c new file mode 100644 index 000000000..4f202e41a --- /dev/null +++ b/pinos/daemon/daemon-config.c @@ -0,0 +1,218 @@ +/* Pinos + * 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 "pinos/daemon/daemon-config.h" + +#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf" + +GQuark +pinos_daemon_config_error_quark (void) +{ + static GQuark quark = 0; + + if (quark == 0) { + quark = g_quark_from_static_string ("pinos_daemon_config_error"); + } + + return quark; +} + +static gboolean +parse_line (PinosDaemonConfig * config, + const gchar * filename, + gchar * line, + guint lineno, + GError ** err) +{ + PinosCommand *command = NULL; + gchar *p; + gboolean ret = TRUE; + GError *local_err = NULL; + + /* search for comments */ + if ((p = strchr (line, '#'))) + *p = '\0'; + + /* remove whitespaces */ + g_strstrip (line); + + if (*line == '\0') /* empty line */ + return TRUE; + + if (!pinos_command_parse (&command, line, &local_err)) { + g_set_error (err, PINOS_DAEMON_CONFIG_ERROR, + PINOS_DAEMON_CONFIG_ERROR_COMMAND, "%s:%u: %s", filename, lineno, + local_err->message); + g_error_free (local_err); + ret = FALSE; + } else { + config->commands = g_list_append (config->commands, command); + } + + return ret; +} + +/** + * pinos_daemon_config_new: + * + * Returns a new empty #PinosDaemonConfig. + */ +PinosDaemonConfig * +pinos_daemon_config_new (void) +{ + PinosDaemonConfig *config; + + config = g_new (PinosDaemonConfig, 1); + + config->commands = NULL; + + return config; +} + +/** + * pinos_daemon_config_free: + * @config: A #PinosDaemonConfig + * + * Free all resources associated to @config. + */ +void +pinos_daemon_config_free (PinosDaemonConfig * config) +{ + g_return_if_fail (config != NULL); + + g_list_free_full (config->commands, (GDestroyNotify) pinos_command_free); + + g_free (config); +} + +/** + * pinos_daemon_config_load_file: + * @config: A #PinosDaemonConfig + * @filename: A filename + * @err: Return location for a #GError, or %NULL + * + * Loads pinos config from @filename. + * + * Returns: %TRUE on success, otherwise %FALSE and @err is set. + */ +gboolean +pinos_daemon_config_load_file (PinosDaemonConfig * config, + const gchar * filename, + GError ** err) +{ + gchar *data; + gchar **lines; + gboolean ret = TRUE; + guint i; + + g_return_val_if_fail (config != NULL, FALSE); + g_return_val_if_fail (filename != NULL && *filename != '\0', FALSE); + + g_debug ("deamon-config %p loading file %s", config, filename); + + if (!g_file_get_contents (filename, &data, NULL, err)) { + return FALSE; + } + + lines = g_strsplit (data, "\n", 0); + for (i = 0; lines[i] != NULL; i++) { + if (!parse_line (config, filename, lines[i], i+1, err)) { + ret = FALSE; + break; + } + } + + g_strfreev (lines); + g_free (data); + + return ret; +} + +/** + * pinos_daemon_config_load: + * @config: A #PinosDaemonConfig + * @err: Return location for a #GError, or %NULL + * + * Loads the default config file for pinos. The filename can be overridden with + * an evironment variable PINOS_CONFIG_FILE. + * + * Return: %TRUE on success, otherwise %FALSE and @err is set. + */ +gboolean +pinos_daemon_config_load (PinosDaemonConfig * config, + GError ** err) +{ + const gchar *filename; + + g_return_val_if_fail (config != NULL, FALSE); + + filename = g_getenv ("PINOS_CONFIG_FILE"); + if (filename != NULL && *filename != '\0') { + g_debug ("PINOS_CONFIG_FILE set to: %s", filename); + } else { + filename = DEFAULT_CONFIG_FILE; + } + + return pinos_daemon_config_load_file (config, filename, err); +} + +/** + * pinos_daemon_config_run_commands: + * @config: A #PinosDaemonConfig + * @daemon: A #PinosDaemon + * + * Run all commands that have been parsed. The list of commands will be cleared + * when this function has been called. + * + * Returns: %TRUE if all commands where executed with success, otherwise %FALSE. + */ +gboolean +pinos_daemon_config_run_commands (PinosDaemonConfig * config, + PinosDaemon * daemon) +{ + GList *walk; + GError *err = NULL; + gboolean ret = TRUE; + + g_return_val_if_fail (config != NULL, FALSE); + + for (walk = config->commands; walk != NULL; walk = walk->next) { + PinosCommand *command = (PinosCommand *)walk->data; + if (!pinos_command_run (command, daemon, &err)) { + g_warning ("could not run command %s: %s", + pinos_command_get_name (command), err->message); + g_clear_error (&err); + ret = FALSE; + } + } + + g_list_free_full (config->commands, (GDestroyNotify) pinos_command_free); + + return ret; +} diff --git a/pinos/daemon/daemon-config.h b/pinos/daemon/daemon-config.h new file mode 100644 index 000000000..1e4f50e3b --- /dev/null +++ b/pinos/daemon/daemon-config.h @@ -0,0 +1,75 @@ +/* Pinos + * 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. + */ + +#ifndef __PINOS_DAEMON_CONFIG_H__ +#define __PINOS_DAEMON_CONFIG_H__ + +#include + +G_BEGIN_DECLS + +#include + +#define PINOS_TYPE_DAEMON_CONFIG (pinos_daemon_config_get_type ()) + +typedef struct _PinosDaemonConfig PinosDaemonConfig; + +struct _PinosDaemonConfig { + GList *commands; +}; + +GQuark pinos_daemon_config_error_quark (void); +/** + * PINOS_DAEMON_CONFIG_ERROR: + * + * Pinos daemon config error. + */ +#define PINOS_DAEMON_CONFIG_ERROR (pinos_daemon_config_error_quark ()) + +/** + * PinosDaemonConfigError: + * @PINOS_DAEMON_CONFIG_ERROR_GENERIC: Generic daemon config error. + * @PINOS_DAEMON_CONFIG_ERROR_ASSIGNMENT: Assignment error. + * @PINOS_DAEMON_CONFIG_ERROR_COMMAND: Command error. + * + * Error codes for Pinos daemon config. + */ +typedef enum +{ + PINOS_DAEMON_CONFIG_ERROR_GENERIC, + PINOS_DAEMON_CONFIG_ERROR_ASSIGNMENT, + PINOS_DAEMON_CONFIG_ERROR_COMMAND, +} PinosDaemonConfigError; + +GType pinos_daemon_config_get_type (void); + +PinosDaemonConfig * pinos_daemon_config_new (void); +void pinos_daemon_config_free (PinosDaemonConfig *config); +gboolean pinos_daemon_config_load_file (PinosDaemonConfig *config, + const gchar *filename, + GError **err); +gboolean pinos_daemon_config_load (PinosDaemonConfig *config, + GError **err); +gboolean pinos_daemon_config_run_commands (PinosDaemonConfig *config, + PinosDaemon *daemon); + +G_END_DECLS + +#endif /* __PINOS_DAEMON_CONFIG_H__ */ diff --git a/pinos/daemon/main.c b/pinos/daemon/main.c index 32fdd4920..455f09d33 100644 --- a/pinos/daemon/main.c +++ b/pinos/daemon/main.c @@ -25,11 +25,14 @@ #include #include +#include "daemon-config.h" + gint main (gint argc, gchar *argv[]) { PinosDaemon *daemon; GMainLoop *loop; + PinosDaemonConfig *config; PinosProperties *props; GError *err = NULL; @@ -38,16 +41,18 @@ main (gint argc, gchar *argv[]) loop = g_main_loop_new (NULL, FALSE); - props = pinos_properties_new ("test", "test", NULL); - daemon = pinos_daemon_new (props); - - if (pinos_module_load (daemon, "module-gst", &err) == NULL) { - g_error ("could not load module-gst: %s", err->message); + /* parse configuration */ + config = pinos_daemon_config_new (); + if (!pinos_daemon_config_load (config, &err)) { + g_error ("failed to parse config: %s", err->message); g_clear_error (&err); } - pinos_spa_alsa_sink_new (daemon, "alsa-sink", NULL); - pinos_spa_v4l2_source_new (daemon, "v4l2-source", NULL); + props = pinos_properties_new ("test", "test", NULL); + daemon = pinos_daemon_new (props); + + pinos_daemon_config_run_commands (config, daemon); + pinos_daemon_start (daemon); g_main_loop_run (loop); diff --git a/pinos/daemon/pinos.conf.in b/pinos/daemon/pinos.conf.in new file mode 100644 index 000000000..89b3ac3d9 --- /dev/null +++ b/pinos/daemon/pinos.conf.in @@ -0,0 +1 @@ +load-module module-gst diff --git a/pinos/modules/gst/module.c b/pinos/modules/gst/module.c index 685f16e16..440e79e46 100644 --- a/pinos/modules/gst/module.c +++ b/pinos/modules/gst/module.c @@ -24,10 +24,10 @@ #include "gst-manager.h" #include "gst-node-factory.h" -gboolean pinos__module_init (PinosModule *module); +gboolean pinos__module_init (PinosModule *module, const gchar * args); G_MODULE_EXPORT gboolean -pinos__module_init (PinosModule * module) +pinos__module_init (PinosModule * module, G_GNUC_UNUSED const gchar * args) { PinosNodeFactory *factory; diff --git a/pinos/modules/spa/module.c b/pinos/modules/spa/module.c new file mode 100644 index 000000000..01506376f --- /dev/null +++ b/pinos/modules/spa/module.c @@ -0,0 +1,36 @@ +/* Pinos + * 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. + */ + +#include +#include + +#include "spa-alsa-sink.h" +#include "spa-v4l2-source.h" + +gboolean pinos__module_init (PinosModule *module, const gchar * args); + +G_MODULE_EXPORT gboolean +pinos__module_init (PinosModule * module, G_GNUC_UNUSED const gchar * args) +{ + pinos_spa_alsa_sink_new (module->daemon, "alsa-sink", NULL); + pinos_spa_v4l2_source_new (module->daemon, "v4l2-source", NULL); + + return TRUE; +} diff --git a/pinos/server/command.c b/pinos/server/command.c new file mode 100644 index 000000000..efe77a438 --- /dev/null +++ b/pinos/server/command.c @@ -0,0 +1,251 @@ +/* Pinos + * 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. + */ + +#include +#include + +#include + +#include "command.h" + +GQuark +pinos_command_error_quark (void) +{ + static GQuark quark = 0; + + if (quark == 0) { + quark = g_quark_from_static_string ("pinos_command_error"); + } + + return quark; +} + +typedef gboolean (*PinosCommandFunc) (PinosCommand *command, + PinosDaemon *daemon, + GError **err); + +static gboolean execute_command_module_load (PinosCommand *command, + PinosDaemon *daemon, + GError **err); + +typedef PinosCommand * (*PinosCommandParseFunc) (const gchar *line, + GError **err); + +static PinosCommand * parse_command_module_load (const gchar *line, + GError **err); + +struct _PinosCommand +{ + PinosCommandFunc func; + gchar **args; + gint n_args; +}; + +typedef struct _CommandParse +{ + const gchar *name; + PinosCommandParseFunc func; +} CommandParse; + +static const CommandParse parsers[] = { + {"load-module", parse_command_module_load}, + {NULL, NULL} +}; + +static const gchar whitespace[] = " \t"; + +static gchar ** +tokenize (const gchar * line, gint max_tokens, gint * n_tokens) +{ + gchar **res; + GSList *tokens, *walk; + const gchar *s; + gint num; + + s = line + strspn (line, whitespace); + num = 0; + tokens = NULL; + + while (*s != '\0' && num + 1 < max_tokens) { + gsize len; + gchar *token; + + len = strcspn (s, whitespace); + token = g_strndup (s, len); + tokens = g_slist_prepend (tokens, token); + num++; + + s += len; + s += strspn (s, whitespace); + } + + if (*s != '\0') { + tokens = g_slist_prepend (tokens, g_strdup (s)); + num++; + } + + res = g_new (gchar *, num + 1); + res[num] = NULL; + for (walk = tokens; walk != NULL; walk = walk->next) { + res[--num] = walk->data; + } + g_slist_free (tokens); + + *n_tokens = num; + + return res; +} + +static PinosCommand * +parse_command_module_load (const gchar * line, GError ** err) +{ + PinosCommand *command; + + command = g_new0 (PinosCommand, 1); + + command->func = execute_command_module_load; + command->args = tokenize (line, 3, &command->n_args); + + if (command->args[1] == NULL) + goto no_module; + + return command; + +no_module: + g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_PARSE, + "%s requires a module name", command->args[0]); + + g_strfreev (command->args); + + return NULL; +} + +static gboolean +execute_command_module_load (PinosCommand * command, + PinosDaemon * daemon, + GError ** err) +{ + gchar *module; + gchar *args; + + module = command->args[1]; + args = command->args[2]; + + return pinos_module_load (daemon, module, args, err) != NULL; +} + +/** + * pinos_command_free: + * @command: A #PinosCommand + * + * Free all resources assicated with @command. + */ +void +pinos_command_free (PinosCommand * command) +{ + g_return_if_fail (command != NULL); + + g_strfreev (command->args); + + g_free (command); +} + +/** + * pinos_command_parse: + * @command: (out): Return location for a #PinosCommand + * @line: command line to parse + * @err: Return location for a #GError, or %NULL + * + * Parses a command line, @line, and store the parsed command in @command. + * A command can later be executed with pinos_command_run(). + * + * Returns: %TRUE on success, %FALSE otherwise. + */ +gboolean +pinos_command_parse (PinosCommand ** command, + gchar * line, + GError ** err) +{ + const CommandParse *parse; + gchar *name; + gsize len; + gboolean ret = FALSE; + + g_return_val_if_fail (command != NULL && *command == NULL, FALSE); + g_return_val_if_fail (line != NULL && *line != '\0', FALSE); + + len = strcspn (line, whitespace); + + name = g_strndup (line, len); + + for (parse = parsers; parse->name != NULL; parse++) { + if (g_strcmp0 (name, parse->name) == 0) { + *command = parse->func (line, err); + if (*command != NULL) + ret = TRUE; + goto out; + } + } + + g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_NO_SUCH_COMMAND, + "Command \"%s\" does not exist", name); + +out: + g_free (name); + + return ret; +} + +/** + * pinos_command_run: + * @command: A #PinosCommand + * @daemon: A #PinosDaemon + * @err: Return location for a #GError, or %NULL + * + * Run @command. + * + * Returns: %TRUE if @command was executed successfully, %FALSE otherwise. + */ +gboolean +pinos_command_run (PinosCommand * command, + PinosDaemon * daemon, + GError ** err) +{ + g_return_val_if_fail (command != NULL, FALSE); + g_return_val_if_fail (PINOS_IS_DAEMON (daemon), FALSE); + + return command->func (command, daemon, err); +} + +/** + * pinos_command_get_name: + * @command: A #PinosCommand + * + * Get the name of @command. + * + * Returns: The name of @command. + */ +const gchar * +pinos_command_get_name (PinosCommand * command) +{ + g_return_val_if_fail (command != NULL, NULL); + + return command->args[0]; +} diff --git a/pinos/server/command.h b/pinos/server/command.h new file mode 100644 index 000000000..f26e2330d --- /dev/null +++ b/pinos/server/command.h @@ -0,0 +1,69 @@ +/* Pinos + * 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. + */ + +#ifndef __PINOS_COMMAND_H__ +#define __PINOS_COMMAND_H__ + +#include + +G_BEGIN_DECLS + +#include + +typedef struct _PinosCommand PinosCommand; + +GQuark pinos_command_error_quark (void); +/** + * PINOS_COMMAND_ERROR: + * + * Pinos command error. + */ +#define PINOS_COMMAND_ERROR (pinos_command_error_quark ()) + +/** + * PinosCommandError: + * @PINOS_COMMAND_ERROR_GENERIC: Generic command error. + * @PINOS_COMMAND_ERROR_NO_SUCH_COMMAND: No such command. + * @PINOS_COMMAND_ERROR_PARSE: Failed to parse command. + * @PINOS_COMMAND_ERROR_FAILED: Command failed to execute. + * + * Error codes for Pinos command. + */ +typedef enum +{ + PINOS_COMMAND_ERROR_GENERIC, + PINOS_COMMAND_ERROR_NO_SUCH_COMMAND, + PINOS_COMMAND_ERROR_PARSE, + PINOS_COMMAND_ERROR_FAILED, +} PinosCommandError; + +void pinos_command_free (PinosCommand *command); + +gboolean pinos_command_parse (PinosCommand **command, + gchar *line, + GError **err); +gboolean pinos_command_run (PinosCommand *command, + PinosDaemon *daemon, + GError **err); +const gchar * pinos_command_get_name (PinosCommand *command); + +G_END_DECLS + +#endif /* __PINOS_COMMAND_H__ */ diff --git a/pinos/server/module.c b/pinos/server/module.c index f725a144b..1f32bffe5 100644 --- a/pinos/server/module.c +++ b/pinos/server/module.c @@ -205,6 +205,7 @@ find_module (const gchar * path, const gchar *name) * pinos_module_load: * @daemon: a #PinosDaemon * @name: name of the module to load + * @args: A string with arguments for the module * @err: Return location for a #GError, or %NULL * * Load module with @name. @@ -212,7 +213,10 @@ find_module (const gchar * path, const gchar *name) * Returns: A #PinosModule if the module could be loaded, or %NULL on failure. */ PinosModule * -pinos_module_load (PinosDaemon * daemon, const gchar * name, GError ** err) +pinos_module_load (PinosDaemon * daemon, + const gchar * name, + const gchar * args, + GError ** err) { PinosModule *module; PinosModulePrivate *priv; @@ -280,7 +284,7 @@ pinos_module_load (PinosDaemon * daemon, const gchar * name, GError ** err) /* don't unload this module again */ g_module_make_resident (gmodule); - if (!init_func (module)) { + if (!init_func (module, (gchar *) args)) { g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_INIT, "\"%s\" failed to initialize", name); g_object_unref (module); diff --git a/pinos/server/module.h b/pinos/server/module.h index be8fb9530..92d681458 100644 --- a/pinos/server/module.h +++ b/pinos/server/module.h @@ -81,18 +81,20 @@ typedef enum /** * PinosModuleInitFunc: * @module: A #PinosModule + * @args: Arguments to the module * * A module should provide an init function with this signature. This function * will be called when a module is loaded. * * Returns: %TRUE on success, %FALSE otherwise */ -typedef gboolean (*PinosModuleInitFunc) (PinosModule *module); +typedef gboolean (*PinosModuleInitFunc) (PinosModule *module, gchar *args); GType pinos_module_get_type (void); PinosModule * pinos_module_load (PinosDaemon *daemon, const gchar *name, + const gchar *args, GError **err); G_END_DECLS diff --git a/pinos/tests/test-client.c b/pinos/tests/test-client.c index 556111495..6a9116337 100644 --- a/pinos/tests/test-client.c +++ b/pinos/tests/test-client.c @@ -18,7 +18,6 @@ */ #include -#include #include #include @@ -27,42 +26,6 @@ static GMainLoop *loop; -static void -on_socket_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) -{ - GSocket *socket; - GstElement *pipeline, *src, *filter; - GBytes *format; - GstCaps *caps; - GError *error = NULL; - - pipeline = gst_parse_launch ("socketsrc name=src ! pinosdepay ! capsfilter name=filter ! videoconvert ! xvimagesink", &error); - if (error != NULL) { - g_warning ("error creating pipeline: %s", error->message); - g_clear_error (&error); - g_assert (pipeline != NULL); - } - - /* configure socket in the socketsrc */ - g_object_get (gobject, "socket", &socket, NULL); - g_print ("got socket %p\n", socket); - src = gst_bin_get_by_name (GST_BIN (pipeline), "src"); - g_object_set (src, "socket", socket, NULL); - - /* configure format as capsfilter */ - g_object_get (gobject, "format", &format, NULL); - caps = gst_caps_from_string (g_bytes_get_data (format, NULL)); - g_bytes_unref (format); - filter = gst_bin_get_by_name (GST_BIN (pipeline), "filter"); - g_object_set (filter, "caps", caps, NULL); - gst_caps_unref (caps); - - /* and set to playing */ - gst_element_set_state (pipeline, GST_STATE_PLAYING); -} - static void on_stream_notify (GObject *gobject, GParamSpec *pspec, @@ -113,7 +76,6 @@ on_state_notify (GObject *gobject, stream = pinos_stream_new (c, "test", NULL); g_signal_connect (stream, "notify::state", (GCallback) on_stream_notify, stream); - g_signal_connect (stream, "notify::socket", (GCallback) on_socket_notify, stream); possible = NULL; pinos_stream_connect (stream, diff --git a/spa/include/spa/node.h b/spa/include/spa/node.h index 1b3904d9c..83c3192d4 100644 --- a/spa/include/spa/node.h +++ b/spa/include/spa/node.h @@ -311,6 +311,8 @@ struct _SpaNode { * * When @format is %NULL, the current format will be removed. * + * This function takes a copy of the format. + * * Returns: #SPA_RESULT_OK on success * #SPA_RESULT_INVALID_ARGUMENTS when node is %NULL * #SPA_RESULT_INVALID_PORT when port_id is not valid @@ -364,12 +366,11 @@ struct _SpaNode { * * For an input port, all the buffers will remain dequeued. Once a buffer * has been pushed on a port with port_push_input, it should not be reused - * until the buffer refcount reached 0 and the notify is called. + * until the REUSE_BUFFER event is notified. * * For output ports, all buffers will be queued in the port. with - * port_pull_output, a buffer can be dequeued. The notify of the buffers - * will be set by @node so that buffers will be reused when the refcount - * reaches 0. + * port_pull_output, a buffer can be dequeued. When a buffer can be reused, + * port_reuse_buffer() should be called. * * Passing %NULL as @buffers will remove the reference that the port has * on the buffers. @@ -395,8 +396,8 @@ struct _SpaNode { * and pushed into the port. A notify should be configured so that you can * know when a buffer can be reused. * - * For output ports, the buffers remain queued. The notify will be configured - * so that buffers can be reused when no longer in use. + * For output ports, the buffers remain queued. port_reuse_buffer() should + * be called when a buffer can be reused. * * Returns: #SPA_RESULT_OK on success */ @@ -407,6 +408,17 @@ struct _SpaNode { SpaBuffer **buffers, unsigned int *n_buffers); + /** + * SpaNode::port_reuse_buffer: + * @node: a #SpaNode + * @port_id: a port id + * @buffer_id: a buffer id to reuse + * + * Tell an output port to reuse a buffer. + * + * Returns: #SPA_RESULT_OK on success + * #SPA_RESULT_INVALID_ARGUMENTS when node is %NULL + */ SpaResult (*port_reuse_buffer) (SpaNode *node, uint32_t port_id, uint32_t buffer_id);