WIP change object model

This commit is contained in:
Wim Taymans 2016-11-14 12:42:00 +01:00
parent 190f01d88e
commit c25ccbb4ba
44 changed files with 1557 additions and 2525 deletions

View file

@ -112,6 +112,9 @@ pinos_array_add_fixed (PinosArray *arr,
return p; return p;
} }
#define pinos_array_add_ptr(a,p) \
*((void**) pinos_array_add (a, sizeof (void*))) = (p)
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif

View file

@ -14,6 +14,7 @@ pinos_headers = [
'subscribe.h', 'subscribe.h',
'thread-mainloop.h', 'thread-mainloop.h',
'transport.h', 'transport.h',
'utils.h',
] ]
pinos_sources = [ pinos_sources = [
@ -33,6 +34,7 @@ pinos_sources = [
'subscribe.c', 'subscribe.c',
'thread-mainloop.c', 'thread-mainloop.c',
'transport.c', 'transport.c',
'utils.c',
gdbus_target, gdbus_target,
] ]

View file

@ -47,7 +47,8 @@ struct _PinosObject {
uint32_t id; uint32_t id;
PinosObjectFlags flags; PinosObjectFlags flags;
PinosDestroyFunc destroy; PinosDestroyFunc destroy;
PinosSignal destroy_signal; PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosObject *object));
unsigned int n_interfaces; unsigned int n_interfaces;
PinosInterface *interfaces; PinosInterface *interfaces;
}; };
@ -81,7 +82,7 @@ static inline void
pinos_object_destroy (PinosObject *object) pinos_object_destroy (PinosObject *object)
{ {
object->flags |= PINOS_OBJECT_FLAG_DESTROYING; object->flags |= PINOS_OBJECT_FLAG_DESTROYING;
pinos_signal_emit (&object->destroy_signal, object, NULL); pinos_signal_emit (&object->destroy_signal, object);
if (object->destroy) if (object->destroy)
object->destroy (object); object->destroy (object);
} }

View file

@ -32,6 +32,7 @@ extern const char g_log_domain_pinos[];
#include <pinos/client/ringbuffer.h> #include <pinos/client/ringbuffer.h>
#include <pinos/client/stream.h> #include <pinos/client/stream.h>
#include <pinos/client/subscribe.h> #include <pinos/client/subscribe.h>
#include <pinos/client/utils.h>
#include <spa/include/spa/id-map.h> #include <spa/include/spa/id-map.h>

View file

@ -31,25 +31,31 @@ typedef struct _PinosListener PinosListener;
struct _PinosListener { struct _PinosListener {
SpaList link; SpaList link;
void (*notify) (PinosListener *listener, void *object, void *data); void (*notify) (void *);
}; };
#if 0
struct _PinosSignal { struct _PinosSignal {
SpaList listeners; SpaList listeners;
void (*notify) (PinosListener *listener, void *object, void *data);
}; };
#endif
static inline void #define PINOS_SIGNAL(name,func) \
pinos_signal_init (PinosSignal *signal) union { \
{ SpaList listeners; \
spa_list_init (&signal->listeners); void (*notify) func; \
} } name;
static inline void #define pinos_signal_init(signal) \
pinos_signal_add (PinosSignal *signal, spa_list_init (&(signal)->listeners);
PinosListener *listener)
{ #define pinos_signal_add(signal,listener,func) \
spa_list_insert (signal->listeners.prev, &listener->link); do { \
} __typeof__((signal)->notify) n = (func); \
(listener)->notify = (void (*) (void *)) n; \
spa_list_insert ((signal)->listeners.prev, &(listener)->link); \
} while (false);
static inline void static inline void
pinos_signal_remove (PinosListener *listener) pinos_signal_remove (PinosListener *listener)
@ -57,16 +63,12 @@ pinos_signal_remove (PinosListener *listener)
spa_list_remove (&listener->link); spa_list_remove (&listener->link);
} }
static inline void #define pinos_signal_emit(signal,...) \
pinos_signal_emit (PinosSignal *signal, do { \
void *object, PinosListener *l, *next; \
void *data) spa_list_for_each_safe (l, next, &(signal)->listeners, link) \
{ ((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__); \
PinosListener *l, *next; } while (false);
spa_list_for_each_safe (l, next, &signal->listeners, link)
l->notify (l, object, data);
}
#ifdef __cplusplus #ifdef __cplusplus
} }

83
pinos/client/utils.c Normal file
View file

@ -0,0 +1,83 @@
/* Simple Plugin API
* Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
*
* 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 <string.h>
#include <pinos/client/array.h>
#include <pinos/client/log.h>
#include <pinos/client/utils.h>
const char *
pinos_split_walk (const char *str,
const char *delimiter,
size_t *len,
const char **state)
{
const char *s = *state ? *state : str;
if (*s == '\0')
return NULL;
*len = strcspn (s, delimiter);
*state = s + *len;
*state += strspn (*state, delimiter);
return s;
}
char **
pinos_split_strv (const char *str,
const char *delimiter,
int max_tokens,
int *n_tokens)
{
const char *state = NULL, *s = NULL;
PinosArray arr;
size_t len;
int n = 0;
pinos_array_init (&arr);
s = pinos_split_walk (str, delimiter, &len, &state);
while (s && n + 1 < max_tokens) {
pinos_array_add_ptr (&arr, strndup (s, len));
s = pinos_split_walk (str, delimiter, &len, &state);
n++;
}
if (s) {
pinos_array_add_ptr (&arr, strdup (s));
n++;
}
pinos_array_add_ptr (&arr, NULL);
*n_tokens = n;
return arr.data;
}
void
pinos_free_strv (char **str)
{
int i;
for (i = 0; str[i]; i++)
free (str[i]);
free (str);
}

View file

@ -1,5 +1,5 @@
/* Pinos /* Simple Plugin API
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com> * Copyright (C) 2016 Wim Taymans <wim.taymans@gmail.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -17,26 +17,29 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#ifndef __PINOS_SPA_ALSA_MONITOR_H__ #ifndef __PINOS_UTILS_H__
#define __PINOS_SPA_ALSA_MONITOR_H__ #define __PINOS_UTILS_H__
#include <glib-object.h> #ifdef __cplusplus
extern "C" {
#endif
#include <spa/defs.h>
#include <spa/include/spa/monitor.h> const char * pinos_split_walk (const char *str,
#include <pinos/server/daemon.h> const char *delimiter,
size_t *len,
const char **state);
G_BEGIN_DECLS char ** pinos_split_strv (const char *str,
const char *delimiter,
int max_tokens,
int *n_tokens);
typedef struct _PinosSpaALSAMonitor PinosSpaALSAMonitor; void pinos_free_strv (char **str);
struct _PinosSpaALSAMonitor { #ifdef __cplusplus
SpaMonitor *monitor; } /* extern "C" */
}; #endif
PinosSpaALSAMonitor * pinos_spa_alsa_monitor_new (PinosCore *core); #endif /* __PINOS_UTILS_H__ */
void pinos_spa_alsa_monitor_destroy (PinosSpaALSAMonitor *monitor);
G_END_DECLS
#endif /* __PINOS_SPA_ALSA_MONITOR_H__ */

View file

@ -22,7 +22,6 @@
#include "config.h" #include "config.h"
#endif #endif
#include <glib.h>
#include <string.h> #include <string.h>
#include <pinos/client/pinos.h> #include <pinos/client/pinos.h>
@ -32,29 +31,17 @@
#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf" #define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf"
GQuark static bool
pinos_daemon_config_error_quark (void) parse_line (PinosDaemonConfig *config,
{ const char *filename,
static GQuark quark = 0; char *line,
unsigned int lineno,
if (quark == 0) { char **err)
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; PinosCommand *command = NULL;
gchar *p; char *p;
gboolean ret = TRUE; bool ret = true;
GError *local_err = NULL; char *local_err = NULL;
/* search for comments */ /* search for comments */
if ((p = strchr (line, '#'))) if ((p = strchr (line, '#')))
@ -64,16 +51,14 @@ parse_line (PinosDaemonConfig * config,
g_strstrip (line); g_strstrip (line);
if (*line == '\0') /* empty line */ if (*line == '\0') /* empty line */
return TRUE; return true;
if (!pinos_command_parse (&command, line, &local_err)) { if ((command = pinos_command_parse (line, &local_err)) == NULL) {
g_set_error (err, PINOS_DAEMON_CONFIG_ERROR, asprintf (err, "%s:%u: %s", filename, lineno, local_err);
PINOS_DAEMON_CONFIG_ERROR_COMMAND, "%s:%u: %s", filename, lineno, free (local_err);
local_err->message); ret = false;
g_error_free (local_err);
ret = FALSE;
} else { } else {
config->commands = g_list_append (config->commands, command); spa_list_insert (config->commands.prev, &command->link);
} }
return ret; return ret;
@ -89,9 +74,8 @@ pinos_daemon_config_new (void)
{ {
PinosDaemonConfig *config; PinosDaemonConfig *config;
config = g_new (PinosDaemonConfig, 1); config = calloc (1, sizeof (PinosDaemonConfig));
spa_list_init (&config->commands);
config->commands = NULL;
return config; return config;
} }
@ -105,52 +89,50 @@ pinos_daemon_config_new (void)
void void
pinos_daemon_config_free (PinosDaemonConfig * config) pinos_daemon_config_free (PinosDaemonConfig * config)
{ {
g_return_if_fail (config != NULL); PinosCommand *cmd, *tmp;
g_list_free_full (config->commands, (GDestroyNotify) pinos_command_free); spa_list_for_each_safe (cmd, tmp, &config->commands, link)
pinos_command_free (cmd);
g_free (config); free (config);
} }
/** /**
* pinos_daemon_config_load_file: * pinos_daemon_config_load_file:
* @config: A #PinosDaemonConfig * @config: A #PinosDaemonConfig
* @filename: A filename * @filename: A filename
* @err: Return location for a #GError, or %NULL * @err: Return location for an error string
* *
* Loads pinos config from @filename. * Loads pinos config from @filename.
* *
* Returns: %TRUE on success, otherwise %FALSE and @err is set. * Returns: %true on success, otherwise %false and @err is set.
*/ */
gboolean bool
pinos_daemon_config_load_file (PinosDaemonConfig * config, pinos_daemon_config_load_file (PinosDaemonConfig *config,
const gchar * filename, const char *filename,
GError ** err) char **err)
{ {
gchar *data; char *data;
gchar **lines; char **lines;
gboolean ret = TRUE; bool ret = true;
guint i; unsigned int i;
int n_lines;
g_return_val_if_fail (config != NULL, FALSE);
g_return_val_if_fail (filename != NULL && *filename != '\0', FALSE);
pinos_log_debug ("deamon-config %p loading file %s", config, filename); pinos_log_debug ("deamon-config %p loading file %s", config, filename);
if (!g_file_get_contents (filename, &data, NULL, err)) { if (!g_file_get_contents (filename, &data, NULL, NULL))
return FALSE; return false;
}
lines = g_strsplit (data, "\n", 0); lines = pinos_split_strv (data, "\n", 0, &n_lines);
for (i = 0; lines[i] != NULL; i++) { for (i = 0; lines[i] != NULL; i++) {
if (!parse_line (config, filename, lines[i], i+1, err)) { if (!parse_line (config, filename, lines[i], i+1, err)) {
ret = FALSE; ret = false;
break; break;
} }
} }
g_strfreev (lines); pinos_free_strv (lines);
g_free (data); free (data);
return ret; return ret;
} }
@ -163,23 +145,20 @@ pinos_daemon_config_load_file (PinosDaemonConfig * config,
* Loads the default config file for pinos. The filename can be overridden with * Loads the default config file for pinos. The filename can be overridden with
* an evironment variable PINOS_CONFIG_FILE. * an evironment variable PINOS_CONFIG_FILE.
* *
* Return: %TRUE on success, otherwise %FALSE and @err is set. * Return: %true on success, otherwise %false and @err is set.
*/ */
gboolean bool
pinos_daemon_config_load (PinosDaemonConfig * config, pinos_daemon_config_load (PinosDaemonConfig *config,
GError ** err) char **err)
{ {
const gchar *filename; const gchar *filename;
g_return_val_if_fail (config != NULL, FALSE); filename = getenv ("PINOS_CONFIG_FILE");
filename = g_getenv ("PINOS_CONFIG_FILE");
if (filename != NULL && *filename != '\0') { if (filename != NULL && *filename != '\0') {
pinos_log_debug ("PINOS_CONFIG_FILE set to: %s", filename); pinos_log_debug ("PINOS_CONFIG_FILE set to: %s", filename);
} else { } else {
filename = DEFAULT_CONFIG_FILE; filename = DEFAULT_CONFIG_FILE;
} }
return pinos_daemon_config_load_file (config, filename, err); return pinos_daemon_config_load_file (config, filename, err);
} }
@ -191,29 +170,27 @@ pinos_daemon_config_load (PinosDaemonConfig * config,
* Run all commands that have been parsed. The list of commands will be cleared * Run all commands that have been parsed. The list of commands will be cleared
* when this function has been called. * when this function has been called.
* *
* Returns: %TRUE if all commands where executed with success, otherwise %FALSE. * Returns: %true if all commands where executed with success, otherwise %false.
*/ */
gboolean bool
pinos_daemon_config_run_commands (PinosDaemonConfig * config, pinos_daemon_config_run_commands (PinosDaemonConfig *config,
PinosDaemon * daemon) PinosDaemon *daemon)
{ {
GList *walk; char *err = NULL;
GError *err = NULL; bool ret = true;
gboolean ret = TRUE; PinosCommand *command, *tmp;
g_return_val_if_fail (config != NULL, FALSE); spa_list_for_each (command, &config->commands, link) {
for (walk = config->commands; walk != NULL; walk = walk->next) {
PinosCommand *command = (PinosCommand *)walk->data;
if (!pinos_command_run (command, daemon->core, &err)) { if (!pinos_command_run (command, daemon->core, &err)) {
pinos_log_warn ("could not run command %s: %s", pinos_log_warn ("could not run command %s: %s", command->name, err);
pinos_command_get_name (command), err->message); free (err);
g_clear_error (&err); ret = false;
ret = FALSE;
} }
} }
g_list_free_full (config->commands, (GDestroyNotify) pinos_command_free); spa_list_for_each_safe (command, tmp, &config->commands, link) {
pinos_command_free (command);
}
return ret; return ret;
} }

View file

@ -27,47 +27,20 @@ G_BEGIN_DECLS
#include <pinos/server/daemon.h> #include <pinos/server/daemon.h>
#define PINOS_TYPE_DAEMON_CONFIG (pinos_daemon_config_get_type ())
typedef struct _PinosDaemonConfig PinosDaemonConfig; typedef struct _PinosDaemonConfig PinosDaemonConfig;
struct _PinosDaemonConfig { struct _PinosDaemonConfig {
GList *commands; SpaList 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); PinosDaemonConfig * pinos_daemon_config_new (void);
void pinos_daemon_config_free (PinosDaemonConfig *config); void pinos_daemon_config_free (PinosDaemonConfig *config);
gboolean pinos_daemon_config_load_file (PinosDaemonConfig *config, bool pinos_daemon_config_load_file (PinosDaemonConfig *config,
const gchar *filename, const char *filename,
GError **err); char **err);
gboolean pinos_daemon_config_load (PinosDaemonConfig *config, bool pinos_daemon_config_load (PinosDaemonConfig *config,
GError **err); char **err);
gboolean pinos_daemon_config_run_commands (PinosDaemonConfig *config, bool pinos_daemon_config_run_commands (PinosDaemonConfig *config,
PinosDaemon *daemon); PinosDaemon *daemon);
G_END_DECLS G_END_DECLS

View file

@ -17,24 +17,21 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <gio/gio.h>
#include <glib.h>
#include <pinos/client/pinos.h> #include <pinos/client/pinos.h>
#include <pinos/server/daemon.h> #include <pinos/server/daemon.h>
#include <pinos/server/module.h> #include <pinos/server/module.h>
#include "daemon-config.h" #include "daemon-config.h"
gint int
main (gint argc, gchar *argv[]) main (int argc, char *argv[])
{ {
PinosCore *core; PinosCore *core;
PinosDaemon *daemon; PinosDaemon *daemon;
PinosMainLoop *loop; PinosMainLoop *loop;
PinosDaemonConfig *config; PinosDaemonConfig *config;
PinosProperties *props; PinosProperties *props;
GError *err = NULL; char *err = NULL;
pinos_init (&argc, &argv); pinos_init (&argc, &argv);
@ -44,8 +41,8 @@ main (gint argc, gchar *argv[])
/* parse configuration */ /* parse configuration */
config = pinos_daemon_config_new (); config = pinos_daemon_config_new ();
if (!pinos_daemon_config_load (config, &err)) { if (!pinos_daemon_config_load (config, &err)) {
g_error ("failed to parse config: %s", err->message); g_error ("failed to parse config: %s", err);
g_clear_error (&err); free (err);
} }
props = pinos_properties_new ("test", "test", NULL); props = pinos_properties_new ("test", "test", NULL);

View file

@ -1,16 +1,12 @@
pinos_module_spa_headers = [ pinos_module_spa_headers = [
'spa-alsa-monitor.h', 'spa-node.h',
'spa-audiotestsrc.h', 'spa-monitor.h',
'spa-v4l2-monitor.h',
'spa-videotestsrc.h',
] ]
pinos_module_spa_sources = [ pinos_module_spa_sources = [
'module.c', 'module.c',
'spa-alsa-monitor.c', 'spa-node.c',
'spa-audiotestsrc.c', 'spa-monitor.c',
'spa-v4l2-monitor.c',
'spa-videotestsrc.c',
] ]
pinos_module_spa_c_args = [ pinos_module_spa_c_args = [

View file

@ -21,20 +21,26 @@
#include <server/daemon.h> #include <server/daemon.h>
#include <server/module.h> #include <server/module.h>
#include "spa-alsa-monitor.h" #include "spa-monitor.h"
#include "spa-v4l2-monitor.h" #include "spa-node.h"
#include "spa-audiotestsrc.h"
#include "spa-videotestsrc.h"
gboolean pinos__module_init (PinosModule *module, const gchar * args); bool pinos__module_init (PinosModule *module, const char * args);
G_MODULE_EXPORT gboolean G_MODULE_EXPORT bool
pinos__module_init (PinosModule * module, G_GNUC_UNUSED const gchar * args) pinos__module_init (PinosModule * module, const char * args)
{ {
pinos_spa_alsa_monitor_new (module->core); pinos_spa_monitor_load (module->core, "build/spa/plugins/alsa/libspa-alsa.so", "alsa-monitor", args);
pinos_spa_v4l2_monitor_new (module->core); pinos_spa_monitor_load (module->core, "build/spa/plugins/v4l2/libspa-v4l2.so", "v4l2-monitor", args);
pinos_spa_audiotestsrc_new (module->core, "audiotestsrc", NULL); pinos_spa_node_load (module->core,
pinos_spa_videotestsrc_new (module->core, "videotestsrc", NULL); "build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc",
"audiotestsrc",
NULL, args);
pinos_spa_node_load (module->core,
"build/spa/plugins/videotestsrc/libspa-videotestsrc.so",
"videotestsrc",
"videotestsrc",
NULL, args);
return TRUE; return TRUE;
} }

View file

@ -1,251 +0,0 @@
/* Pinos
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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 <dlfcn.h>
#include <errno.h>
#include <poll.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <spa/include/spa/node.h>
#include <spa/include/spa/monitor.h>
#include <pinos/client/log.h>
#include <pinos/server/node.h>
#include "spa-alsa-monitor.h"
typedef struct
{
PinosSpaALSAMonitor this;
PinosObject object;
PinosCore *core;
SpaHandle *handle;
GHashTable *nodes;
} PinosSpaALSAMonitorImpl;
static SpaResult
make_handle (PinosCore *core, SpaHandle **handle, const char *lib, const char *name, const SpaDict *info)
{
SpaResult res;
void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
g_error ("can't load %s: %s", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
g_error ("can't find enum function");
return SPA_RESULT_ERROR;
}
while (true) {
const SpaHandleFactory *factory;
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
g_error ("can't enumerate factories: %d", res);
break;
}
if (strcmp (factory->name, name))
continue;
*handle = g_malloc0 (factory->size);
if ((res = spa_handle_factory_init (factory, *handle, info, core->support, core->n_support)) < 0) {
g_error ("can't make factory instance: %d", res);
return res;
}
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void
add_item (PinosSpaALSAMonitor *this, SpaMonitorItem *item)
{
PinosSpaALSAMonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaALSAMonitorImpl, this);
SpaResult res;
SpaHandle *handle;
PinosNode *node;
void *node_iface, *clock_iface;
PinosProperties *props = NULL;
pinos_log_debug ("alsa-monitor %p: add: \"%s\" (%s)", this, item->name, item->id);
handle = calloc (1, item->factory->size);
if ((res = spa_handle_factory_init (item->factory,
handle,
item->info,
impl->core->support,
impl->core->n_support)) < 0) {
g_error ("can't make factory instance: %d", res);
return;
}
if ((res = spa_handle_get_interface (handle, impl->core->registry.uri.spa_node, &node_iface)) < 0) {
g_error ("can't get NODE interface: %d", res);
return;
}
if ((res = spa_handle_get_interface (handle, impl->core->registry.uri.spa_clock, &clock_iface)) < 0) {
pinos_log_debug ("can't get CLOCK interface: %d", res);
clock_iface = NULL;
}
if (item->info) {
unsigned int i;
props = pinos_properties_new (NULL, NULL);
for (i = 0; i < item->info->n_items; i++)
pinos_properties_set (props,
item->info->items[i].key,
item->info->items[i].value);
}
node = pinos_node_new (impl->core,
item->factory->name,
node_iface,
clock_iface,
props);
g_hash_table_insert (impl->nodes, strdup (item->id), node);
}
static void
remove_item (PinosSpaALSAMonitor *this, SpaMonitorItem *item)
{
PinosSpaALSAMonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaALSAMonitorImpl, this);
PinosNode *node;
pinos_log_debug ("alsa-monitor %p: remove: \"%s\" (%s)", this, item->name, item->id);
node = g_hash_table_lookup (impl->nodes, item->id);
if (node) {
pinos_node_destroy (node);
g_hash_table_remove (impl->nodes, item->id);
}
}
static void
on_monitor_event (SpaMonitor *monitor,
SpaMonitorEvent *event,
void *user_data)
{
PinosSpaALSAMonitorImpl *impl = SPA_CONTAINER_OF (monitor, PinosSpaALSAMonitorImpl, this);
PinosSpaALSAMonitor *this = &impl->this;
switch (event->type) {
case SPA_MONITOR_EVENT_TYPE_ADDED:
{
SpaMonitorItem *item = (SpaMonitorItem *) event;
add_item (this, item);
break;
}
case SPA_MONITOR_EVENT_TYPE_REMOVED:
{
SpaMonitorItem *item = (SpaMonitorItem *) event;
remove_item (this, item);
}
case SPA_MONITOR_EVENT_TYPE_CHANGED:
{
SpaMonitorItem *item = (SpaMonitorItem *) event;
pinos_log_debug ("alsa-monitor %p: changed: \"%s\"", this, item->name);
break;
}
default:
break;
}
}
static void
monitor_destroy (PinosObject * object)
{
PinosSpaALSAMonitorImpl *impl = SPA_CONTAINER_OF (object, PinosSpaALSAMonitorImpl, object);
PinosSpaALSAMonitor *this = &impl->this;
pinos_log_debug ("spa-monitor %p: destroy", this);
spa_handle_clear (impl->handle);
free (impl->handle);
g_hash_table_unref (impl->nodes);
free (impl);
}
PinosSpaALSAMonitor *
pinos_spa_alsa_monitor_new (PinosCore *core)
{
PinosSpaALSAMonitorImpl *impl;
PinosSpaALSAMonitor *this;
SpaHandle *handle;
SpaResult res;
void *iface;
void *state = NULL;
if ((res = make_handle (core, &handle,
"build/spa/plugins/alsa/libspa-alsa.so",
"alsa-monitor",
NULL)) < 0) {
g_error ("can't create alsa-monitor: %d", res);
return NULL;
}
if ((res = spa_handle_get_interface (handle,
core->registry.uri.spa_monitor,
&iface)) < 0) {
free (handle);
pinos_log_error ("can't get MONITOR interface: %d", res);
return NULL;
}
impl = calloc (1, sizeof (PinosSpaALSAMonitorImpl));
impl->core = core;
this = &impl->this;
this->monitor = iface;
pinos_object_init (&impl->object,
impl->core->registry.uri.monitor,
this,
monitor_destroy);
impl->nodes = g_hash_table_new_full (g_str_hash,
g_str_equal,
free,
NULL);
while (true) {
SpaMonitorItem *item;
if ((res = spa_monitor_enum_items (this->monitor, &item, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
pinos_log_debug ("spa_monitor_enum_items: got error %d\n", res);
break;
}
add_item (this, item);
}
spa_monitor_set_event_callback (this->monitor, on_monitor_event, impl);
return this;
}

View file

@ -1,207 +0,0 @@
/* Pinos
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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 <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <spa/include/spa/node.h>
#include "spa-audiotestsrc.h"
#define PINOS_SPA_AUDIOTESTSRC_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SPA_AUDIOTESTSRC, PinosSpaAudioTestSrcPrivate))
struct _PinosSpaAudioTestSrcPrivate
{
PinosRingbuffer *ringbuffer;
SpaHandle *handle;
};
enum {
PROP_0,
};
G_DEFINE_TYPE (PinosSpaAudioTestSrc, pinos_spa_audiotestsrc, PINOS_TYPE_NODE);
static SpaResult
make_node (PinosDaemon *daemon, SpaHandle **handle, SpaNode **node, const char *lib, const char *name)
{
SpaResult res;
void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
g_error ("can't load %s: %s", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
g_error ("can't find enum function");
return SPA_RESULT_ERROR;
}
while (true) {
const SpaHandleFactory *factory;
void *iface;
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
g_error ("can't enumerate factories: %d", res);
break;
}
if (strcmp (factory->name, name))
continue;
*handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory,
*handle,
NULL,
daemon->support,
daemon->n_support)) < 0) {
g_error ("can't make factory instance: %d", res);
return res;
}
if ((res = spa_handle_get_interface (*handle,
daemon->registry.uri.spa_node,
&iface)) < 0) {
g_error ("can't get interface %d", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void
setup_node (PinosSpaAudioTestSrc *this)
{
#if 0
PinosNode *node = PINOS_NODE (this);
SpaResult res;
SpaProps *props;
SpaPropValue value;
if ((res = spa_node_get_props (node->node, &props)) < 0)
pinos_log_debug ("got get_props error %d", res);
if ((res = spa_node_set_props (node->node, props)) < 0)
pinos_log_debug ("got set_props error %d", res);
#endif
}
static void
get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
src_constructed (GObject * object)
{
PinosSpaAudioTestSrc *src = PINOS_SPA_AUDIOTESTSRC (object);
setup_node (src);
G_OBJECT_CLASS (pinos_spa_audiotestsrc_parent_class)->constructed (object);
}
static void
src_finalize (GObject * object)
{
PinosSpaAudioTestSrc *src = PINOS_SPA_AUDIOTESTSRC (object);
PinosSpaAudioTestSrcPrivate *priv = src->priv;
pinos_log_debug ("audiotestsrc %p: dispose", src);
spa_handle_clear (priv->handle);
g_free (priv->handle);
G_OBJECT_CLASS (pinos_spa_audiotestsrc_parent_class)->finalize (object);
}
static void
pinos_spa_audiotestsrc_class_init (PinosSpaAudioTestSrcClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosSpaAudioTestSrcPrivate));
gobject_class->constructed = src_constructed;
gobject_class->finalize = src_finalize;
gobject_class->get_property = get_property;
gobject_class->set_property = set_property;
}
static void
pinos_spa_audiotestsrc_init (PinosSpaAudioTestSrc * this)
{
this->priv = PINOS_SPA_AUDIOTESTSRC_GET_PRIVATE (this);
}
PinosNode *
pinos_spa_audiotestsrc_new (PinosDaemon *daemon,
const gchar *name,
PinosProperties *properties)
{
PinosNode *node;
SpaNode *n;
SpaResult res;
SpaHandle *handle;
if ((res = make_node (daemon,
&handle,
&n,
"build/spa/plugins/audiotestsrc/libspa-audiotestsrc.so",
"audiotestsrc")) < 0) {
g_error ("can't create audiotestsrc: %d", res);
return NULL;
}
node = g_object_new (PINOS_TYPE_SPA_AUDIOTESTSRC,
"daemon", daemon,
"name", name,
"properties", properties,
"node", n,
NULL);
PINOS_SPA_AUDIOTESTSRC (node)->priv->handle = handle;
return node;
}

View file

@ -1,36 +0,0 @@
/* Pinos
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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_SPA_AUDIOTESTSRC_H__
#define __PINOS_SPA_AUDIOTESTSRC_H__
#include <glib-object.h>
#include <client/pinos.h>
#include <server/node.h>
G_BEGIN_DECLS
PinosNode * pinos_spa_audiotestsrc_new (PinosCore *core,
const gchar *name,
PinosProperties *properties);
G_END_DECLS
#endif /* __PINOS_SPA_AUDIOTESTSRC_H__ */

View file

@ -31,70 +31,23 @@
#include <pinos/client/log.h> #include <pinos/client/log.h>
#include <pinos/server/node.h> #include <pinos/server/node.h>
#include "spa-v4l2-monitor.h" #include "spa-monitor.h"
typedef struct typedef struct
{ {
PinosSpaV4l2Monitor this; PinosSpaMonitor this;
PinosObject object;
PinosCore *core; PinosCore *core;
SpaHandle *handle; void *hnd;
GHashTable *nodes; GHashTable *nodes;
} PinosSpaV4l2MonitorImpl; } PinosSpaMonitorImpl;
static SpaResult
make_handle (PinosCore *core,
SpaHandle **handle,
const char *lib,
const char *name,
const SpaDict *info)
{
SpaResult res;
void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
pinos_log_error ("can't load %s: %s", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
pinos_log_error ("can't find enum function");
return SPA_RESULT_ERROR;
}
while (true) {
const SpaHandleFactory *factory;
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
pinos_log_error ("can't enumerate factories: %d", res);
break;
}
if (strcmp (factory->name, name))
continue;
*handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory,
*handle,
info,
core->support,
core->n_support)) < 0) {
pinos_log_error ("can't make factory instance: %d", res);
return res;
}
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void static void
add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item) add_item (PinosSpaMonitor *this, SpaMonitorItem *item)
{ {
PinosSpaV4l2MonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaV4l2MonitorImpl, this); PinosSpaMonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaMonitorImpl, this);
SpaResult res; SpaResult res;
SpaHandle *handle; SpaHandle *handle;
PinosNode *node; PinosNode *node;
@ -102,7 +55,7 @@ add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item)
void *clock_iface; void *clock_iface;
PinosProperties *props = NULL; PinosProperties *props = NULL;
pinos_log_debug ("v4l2-monitor %p: add: \"%s\" (%s)", this, item->name, item->id); pinos_log_debug ("monitor %p: add: \"%s\" (%s)", this, item->name, item->id);
handle = calloc (1, item->factory->size); handle = calloc (1, item->factory->size);
if ((res = spa_handle_factory_init (item->factory, if ((res = spa_handle_factory_init (item->factory,
@ -143,12 +96,12 @@ add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item)
} }
static void static void
remove_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item) remove_item (PinosSpaMonitor *this, SpaMonitorItem *item)
{ {
PinosSpaV4l2MonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaV4l2MonitorImpl, this); PinosSpaMonitorImpl *impl = SPA_CONTAINER_OF (this, PinosSpaMonitorImpl, this);
PinosNode *node; PinosNode *node;
pinos_log_debug ("v4l2-monitor %p: remove: \"%s\" (%s)", this, item->name, item->id); pinos_log_debug ("monitor %p: remove: \"%s\" (%s)", this, item->name, item->id);
node = g_hash_table_lookup (impl->nodes, item->id); node = g_hash_table_lookup (impl->nodes, item->id);
if (node) { if (node) {
@ -162,7 +115,7 @@ on_monitor_event (SpaMonitor *monitor,
SpaMonitorEvent *event, SpaMonitorEvent *event,
void *user_data) void *user_data)
{ {
PinosSpaV4l2Monitor *this = user_data; PinosSpaMonitor *this = user_data;
switch (event->type) { switch (event->type) {
case SPA_MONITOR_EVENT_TYPE_ADDED: case SPA_MONITOR_EVENT_TYPE_ADDED:
@ -179,7 +132,7 @@ on_monitor_event (SpaMonitor *monitor,
case SPA_MONITOR_EVENT_TYPE_CHANGED: case SPA_MONITOR_EVENT_TYPE_CHANGED:
{ {
SpaMonitorItem *item = (SpaMonitorItem *) event; SpaMonitorItem *item = (SpaMonitorItem *) event;
pinos_log_debug ("v4l2-monitor %p: changed: \"%s\"", this, item->name); pinos_log_debug ("monitor %p: changed: \"%s\"", this, item->name);
break; break;
} }
default: default:
@ -187,64 +140,74 @@ on_monitor_event (SpaMonitor *monitor,
} }
} }
static void PinosSpaMonitor *
monitor_destroy (PinosObject * object) pinos_spa_monitor_load (PinosCore *core,
const char *lib,
const char *factory_name,
const char *args)
{ {
PinosSpaV4l2MonitorImpl *impl = SPA_CONTAINER_OF (object, PinosSpaV4l2MonitorImpl, object); PinosSpaMonitorImpl *impl;
PinosSpaV4l2Monitor *this = &impl->this; PinosSpaMonitor *this;
pinos_log_debug ("spa-monitor %p: dispose", this);
spa_handle_clear (impl->handle);
free (impl->handle);
g_hash_table_unref (impl->nodes);
free (impl);
}
PinosSpaV4l2Monitor *
pinos_spa_v4l2_monitor_new (PinosCore *core)
{
PinosSpaV4l2MonitorImpl *impl;
PinosSpaV4l2Monitor *this;
SpaHandle *handle; SpaHandle *handle;
SpaResult res; SpaResult res;
void *iface; void *iface;
void *state = NULL; void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
const SpaHandleFactory *factory;
if ((res = make_handle (core, if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
&handle, pinos_log_error ("can't load %s: %s", lib, dlerror());
"build/spa/plugins/v4l2/libspa-v4l2.so",
"v4l2-monitor",
NULL)) < 0) {
pinos_log_error ("can't create v4l2-monitor: %d", res);
return NULL; return NULL;
} }
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
pinos_log_error ("can't find enum function");
goto no_symbol;
}
while (true) {
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
pinos_log_error ("can't enumerate factories: %d", res);
goto enum_failed;
}
if (strcmp (factory->name, factory_name) == 0)
break;
}
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory,
handle,
NULL,
core->support,
core->n_support)) < 0) {
pinos_log_error ("can't make factory instance: %d", res);
goto init_failed;
}
if ((res = spa_handle_get_interface (handle, if ((res = spa_handle_get_interface (handle,
core->registry.uri.spa_monitor, core->registry.uri.spa_monitor,
&iface)) < 0) { &iface)) < 0) {
free (handle); free (handle);
pinos_log_error ("can't get MONITOR interface: %d", res); pinos_log_error ("can't get MONITOR interface: %d", res);
return NULL; goto interface_failed;
} }
impl = calloc (1, sizeof (PinosSpaV4l2MonitorImpl)); impl = calloc (1, sizeof (PinosSpaMonitorImpl));
impl->core = core; impl->core = core;
impl->hnd = hnd;
pinos_object_init (&impl->object,
core->registry.uri.monitor,
impl,
monitor_destroy);
this = &impl->this; this = &impl->this;
pinos_signal_init (&this->destroy_signal);
this->monitor = iface; this->monitor = iface;
this->lib = strdup (lib);
this->factory_name = strdup (factory_name);
this->handle = handle;
impl->nodes = g_hash_table_new_full (g_str_hash, impl->nodes = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, free,
g_object_unref); NULL);
while (TRUE) { state = NULL;
while (true) {
SpaMonitorItem *item; SpaMonitorItem *item;
SpaResult res; SpaResult res;
@ -257,7 +220,32 @@ pinos_spa_v4l2_monitor_new (PinosCore *core)
} }
spa_monitor_set_event_callback (this->monitor, on_monitor_event, this); spa_monitor_set_event_callback (this->monitor, on_monitor_event, this);
pinos_registry_add_object (&core->registry, &impl->object);
return this; return this;
interface_failed:
spa_handle_clear (handle);
init_failed:
free (handle);
enum_failed:
no_symbol:
dlclose (hnd);
return NULL;
}
void
pinos_spa_monitor_destroy (PinosSpaMonitor * monitor)
{
PinosSpaMonitorImpl *impl = SPA_CONTAINER_OF (monitor, PinosSpaMonitorImpl, this);
pinos_log_debug ("spa-monitor %p: dispose", impl);
pinos_signal_emit (&monitor->destroy_signal, monitor);
spa_handle_clear (monitor->handle);
free (monitor->handle);
free (monitor->lib);
free (monitor->factory_name);
g_hash_table_unref (impl->nodes);
dlclose (impl->hnd);
free (impl);
} }

View file

@ -17,26 +17,36 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#ifndef __PINOS_SPA_V4L2_MONITOR_H__ #ifndef __PINOS_SPA_MONITOR_H__
#define __PINOS_SPA_V4L2_MONITOR_H__ #define __PINOS_SPA_MONITOR_H__
#include <pinos/server/core.h> #include <pinos/server/core.h>
#include <spa/include/spa/monitor.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef struct _PinosSpaV4l2Monitor PinosSpaV4l2Monitor; typedef struct _PinosSpaMonitor PinosSpaMonitor;
struct _PinosSpaV4l2Monitor { struct _PinosSpaMonitor {
SpaMonitor *monitor; SpaMonitor *monitor;
char *lib;
char *factory_name;
SpaHandle *handle;
PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosSpaMonitor *monitor));
}; };
PinosSpaV4l2Monitor * pinos_spa_v4l2_monitor_new (PinosCore *core); PinosSpaMonitor * pinos_spa_monitor_load (PinosCore *core,
void pinos_spa_v4l2_monitor_destroy (PinosSpaV4l2Monitor *monitor); const char *lib,
const char *factory_name,
const char *args);
void pinos_spa_monitor_destroy (PinosSpaMonitor *monitor);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* __PINOS_SPA_V4L2_MONITOR_H__ */ #endif /* __PINOS_SPA_MONITOR_H__ */

View file

@ -0,0 +1,138 @@
/* Pinos
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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 <string.h>
#include <stdio.h>
#include <dlfcn.h>
#include <spa/include/spa/node.h>
#include "spa-node.h"
typedef struct {
PinosSpaNode this;
PinosCore *core;
void *hnd;
} PinosSpaNodeImpl;
PinosSpaNode *
pinos_spa_node_load (PinosCore *core,
const char *lib,
const char *factory_name,
const char *name,
PinosProperties *properties,
const char *args)
{
PinosSpaNode *this;
PinosSpaNodeImpl *impl;
SpaNode *spa_node;
SpaClock *spa_clock;
SpaResult res;
SpaHandle *handle;
void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
const SpaHandleFactory *factory;
void *iface;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
pinos_log_error ("can't load %s: %s", lib, dlerror());
return NULL;
}
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
pinos_log_error ("can't find enum function");
goto no_symbol;
}
while (true) {
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
pinos_log_error ("can't enumerate factories: %d", res);
goto enum_failed;
}
if (strcmp (factory->name, factory_name) == 0)
break;
}
handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory,
handle,
NULL,
core->support,
core->n_support)) < 0) {
pinos_log_error ("can't make factory instance: %d", res);
goto init_failed;
}
if ((res = spa_handle_get_interface (handle,
core->registry.uri.spa_node,
&iface)) < 0) {
pinos_log_error ("can't get interface %d", res);
goto interface_failed;
}
spa_node = iface;
if ((res = spa_handle_get_interface (handle,
core->registry.uri.spa_clock,
&iface)) < 0) {
iface = NULL;
}
spa_clock = iface;
impl = calloc (1, sizeof (PinosSpaNodeImpl));
impl->core = core;
impl->hnd = hnd;
this = &impl->this;
this->node = pinos_node_new (core,
name,
spa_node,
spa_clock,
properties);
this->lib = strdup (lib);
this->factory_name = strdup (factory_name);
this->handle = handle;
return this;
interface_failed:
spa_handle_clear (handle);
init_failed:
free (handle);
enum_failed:
no_symbol:
dlclose (hnd);
return NULL;
}
void
pinos_spa_node_destroy (PinosSpaNode * node)
{
PinosSpaNodeImpl *impl = SPA_CONTAINER_OF (node, PinosSpaNodeImpl, this);
pinos_log_debug ("spa-node %p: destroy", impl);
pinos_signal_emit (&node->destroy_signal, node);
pinos_node_destroy (node->node);
spa_handle_clear (node->handle);
free (node->handle);
free (node->lib);
free (node->factory_name);
dlclose (impl->hnd);
free (impl);
}

View file

@ -0,0 +1,52 @@
/* Pinos
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* 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_SPA_NODE_H__
#define __PINOS_SPA_NODE_H__
#include <server/core.h>
#include <server/node.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _PinosSpaNode PinosSpaNode;
struct _PinosSpaNode {
PinosNode *node;
char *lib;
char *factory_name;
SpaHandle *handle;
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosSpaNode *node));
};
PinosSpaNode * pinos_spa_node_load (PinosCore *core,
const char *lib,
const char *factory_name,
const char *name,
PinosProperties *properties,
const char *args);
#ifdef __cplusplus
}
#endif
#endif /* __PINOS_SPA_NODE_H__ */

View file

@ -1,172 +0,0 @@
/* Pinos
* Copyright (C) 2016 Axis Communications AB
*
* 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 <dlfcn.h>
#include <spa/include/spa/node.h>
#include <spa/include/spa/video/format.h>
#include "spa-videotestsrc.h"
#define PINOS_SPA_VIDEOTESTSRC_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SPA_VIDEOTESTSRC, PinosSpaVideoTestSrcPrivate))
struct _PinosSpaVideoTestSrcPrivate
{
SpaHandle *handle;
};
enum {
PROP_0,
};
G_DEFINE_TYPE (PinosSpaVideoTestSrc, pinos_spa_videotestsrc, PINOS_TYPE_NODE);
static SpaResult
make_node (PinosDaemon *daemon, SpaHandle **handle, SpaNode **node, const char *lib, const char *name)
{
SpaResult res;
void *hnd, *state = NULL;
SpaEnumHandleFactoryFunc enum_func;
if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) {
g_error ("can't load %s: %s", lib, dlerror());
return SPA_RESULT_ERROR;
}
if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) {
g_error ("can't find enum function");
return SPA_RESULT_ERROR;
}
while (true) {
const SpaHandleFactory *factory;
void *iface;
if ((res = enum_func (&factory, &state)) < 0) {
if (res != SPA_RESULT_ENUM_END)
g_error ("can't enumerate factories: %d", res);
break;
}
if (strcmp (factory->name, name))
continue;
*handle = calloc (1, factory->size);
if ((res = spa_handle_factory_init (factory, *handle, NULL, daemon->support, daemon->n_support)) < 0) {
g_error ("can't make factory instance: %d", res);
return res;
}
if ((res = spa_handle_get_interface (*handle,
daemon->registry.uri.spa_node,
&iface)) < 0) {
g_error ("can't get interface %d", res);
return res;
}
*node = iface;
return SPA_RESULT_OK;
}
return SPA_RESULT_ERROR;
}
static void
get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
source_finalize (GObject * object)
{
PinosSpaVideoTestSrc *source = PINOS_SPA_VIDEOTESTSRC (object);
PinosSpaVideoTestSrcPrivate *priv = source->priv;
g_debug ("spa-source %p: dispose", source);
spa_handle_clear (priv->handle);
g_free (priv->handle);
G_OBJECT_CLASS (pinos_spa_videotestsrc_parent_class)->finalize (object);
}
static void
pinos_spa_videotestsrc_class_init (PinosSpaVideoTestSrcClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosSpaVideoTestSrcPrivate));
gobject_class->finalize = source_finalize;
gobject_class->get_property = get_property;
gobject_class->set_property = set_property;
}
static void
pinos_spa_videotestsrc_init (PinosSpaVideoTestSrc * source)
{
source->priv = PINOS_SPA_VIDEOTESTSRC_GET_PRIVATE (source);
}
PinosNode *
pinos_spa_videotestsrc_new (PinosDaemon *daemon,
const gchar *name,
PinosProperties *properties)
{
PinosNode *node;
SpaNode *n;
SpaResult res;
SpaHandle *handle;
if ((res = make_node (daemon,
&handle,
&n,
"build/spa/plugins/videotestsrc/libspa-videotestsrc.so",
"videotestsrc")) < 0) {
g_error ("can't create videotestsrc: %d", res);
return NULL;
}
node = g_object_new (PINOS_TYPE_SPA_VIDEOTESTSRC,
"daemon", daemon,
"name", name,
"properties", properties,
"node", n,
NULL);
PINOS_SPA_VIDEOTESTSRC (node)->priv->handle = handle;
return node;
}

View file

@ -1,43 +0,0 @@
/* Pinos
* Copyright (C) 2016 Axis Communications AB
*
* 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_SPA_VIDEOTESTSRC_H__
#define __PINOS_SPA_VIDEOTESTSRC_H__
#include <glib-object.h>
#include <client/pinos.h>
#include <server/node.h>
typedef struct _PinosSpaVideoTestSrc PinosSpaVideoTestSrc;
G_BEGIN_DECLS
struct _PinosSpaVideoTestSrc {
PinosNode *node;
};
PinosSpaVideoTestSrc * pinos_spa_videotestsrc_new (PinosCore *core,
const gchar *name,
PinosProperties *properties);
void pinos_spa_videotestsrc_destroy (PinosSpaVideoTestSrc *src);
G_END_DECLS
#endif /* __PINOS_SPA_VIDEOTESTSRC_H__ */

View file

@ -102,12 +102,12 @@ struct _SpaProxy
SpaNodeEventCallback event_cb; SpaNodeEventCallback event_cb;
void *user_data; void *user_data;
SpaPollFd fds[1]; SpaPollFd ctrl_fds[1];
SpaPollItem poll; SpaPollItem ctrl_poll;
PinosConnection *conn; PinosConnection *conn;
SpaPollFd rtfds[1]; SpaPollFd data_fds[1];
SpaPollItem rtpoll; SpaPollItem data_poll;
unsigned int max_inputs; unsigned int max_inputs;
unsigned int n_inputs; unsigned int n_inputs;
@ -123,17 +123,15 @@ typedef struct
{ {
PinosClientNode this; PinosClientNode this;
PinosObject object;
PinosInterface ifaces[1];
PinosCore *core; PinosCore *core;
SpaProxy proxy; SpaProxy proxy;
PinosListener transport_changed; PinosListener transport_changed;
PinosListener loop_changed;
int fd; int ctrl_fd;
int rtfd; int data_fd;
} PinosClientNodeImpl; } PinosClientNodeImpl;
static void static void
@ -862,7 +860,7 @@ spa_proxy_node_port_reuse_buffer (SpaNode *node,
rb.buffer_id = buffer_id; rb.buffer_id = buffer_id;
pinos_transport_add_event (pnode->transport, &rb.event); pinos_transport_add_event (pnode->transport, &rb.event);
cmd = PINOS_TRANSPORT_CMD_HAVE_EVENT; cmd = PINOS_TRANSPORT_CMD_HAVE_EVENT;
write (this->rtfds[0].fd, &cmd, 1); write (this->data_fds[0].fd, &cmd, 1);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -931,7 +929,7 @@ spa_proxy_node_process_input (SpaNode *node)
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
cmd = PINOS_TRANSPORT_CMD_HAVE_DATA; cmd = PINOS_TRANSPORT_CMD_HAVE_DATA;
write (this->rtfds[0].fd, &cmd, 1); write (this->data_fds[0].fd, &cmd, 1);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -1105,7 +1103,7 @@ proxy_on_fd_events (SpaPollNotifyData *data)
} }
static int static int
proxy_on_rtfd_events (SpaPollNotifyData *data) proxy_on_data_fd_events (SpaPollNotifyData *data)
{ {
SpaProxy *this = data->user_data; SpaProxy *this = data->user_data;
PinosNode *pnode = this->pnode; PinosNode *pnode = this->pnode;
@ -1113,7 +1111,7 @@ proxy_on_rtfd_events (SpaPollNotifyData *data)
if (data->fds[0].revents & POLLIN) { if (data->fds[0].revents & POLLIN) {
uint8_t cmd; uint8_t cmd;
read (this->rtfds[0].fd, &cmd, 1); read (this->data_fds[0].fd, &cmd, 1);
if (cmd & PINOS_TRANSPORT_CMD_HAVE_EVENT) { if (cmd & PINOS_TRANSPORT_CMD_HAVE_EVENT) {
SpaNodeEvent event; SpaNodeEvent event;
@ -1194,41 +1192,39 @@ proxy_init (SpaProxy *this,
this->node = proxy_node; this->node = proxy_node;
this->fds[0].fd = -1; this->ctrl_fds[0].fd = -1;
this->fds[0].events = POLLIN | POLLPRI | POLLERR; this->ctrl_fds[0].events = POLLIN | POLLPRI | POLLERR;
this->fds[0].revents = 0; this->ctrl_fds[0].revents = 0;
this->poll.id = 0; this->ctrl_poll.id = 0;
this->poll.enabled = true; this->ctrl_poll.enabled = true;
this->poll.fds = this->fds; this->ctrl_poll.fds = this->ctrl_fds;
this->poll.n_fds = 1; this->ctrl_poll.n_fds = 1;
this->poll.idle_cb = NULL; this->ctrl_poll.idle_cb = NULL;
this->poll.before_cb = NULL; this->ctrl_poll.before_cb = NULL;
this->poll.after_cb = proxy_on_fd_events; this->ctrl_poll.after_cb = proxy_on_fd_events;
this->poll.user_data = this; this->ctrl_poll.user_data = this;
this->rtfds[0].fd = -1; this->data_fds[0].fd = -1;
this->rtfds[0].events = POLLIN | POLLPRI | POLLERR; this->data_fds[0].events = POLLIN | POLLPRI | POLLERR;
this->rtfds[0].revents = 0; this->data_fds[0].revents = 0;
this->rtpoll.id = 0; this->data_poll.id = 0;
this->rtpoll.enabled = true; this->data_poll.enabled = true;
this->rtpoll.fds = this->rtfds; this->data_poll.fds = this->data_fds;
this->rtpoll.n_fds = 1; this->data_poll.n_fds = 1;
this->rtpoll.idle_cb = NULL; this->data_poll.idle_cb = NULL;
this->rtpoll.before_cb = NULL; this->data_poll.before_cb = NULL;
this->rtpoll.after_cb = proxy_on_rtfd_events; this->data_poll.after_cb = proxy_on_data_fd_events;
this->rtpoll.user_data = this; this->data_poll.user_data = this;
return SPA_RESULT_RETURN_ASYNC (this->seq++); return SPA_RESULT_RETURN_ASYNC (this->seq++);
} }
static void static void
on_transport_changed (PinosListener *listener, on_transport_changed (PinosListener *listener,
void *object, PinosNode *node)
void *data)
{ {
PinosClientNodeImpl *impl = SPA_CONTAINER_OF (listener, PinosClientNodeImpl, transport_changed); PinosClientNodeImpl *impl = SPA_CONTAINER_OF (listener, PinosClientNodeImpl, transport_changed);
PinosClientNode *this = &impl->this; PinosClientNode *this = &impl->this;
PinosNode *node = object;
PinosTransportInfo info; PinosTransportInfo info;
PinosMessageTransportUpdate tu; PinosMessageTransportUpdate tu;
PinosConnection *conn = impl->proxy.conn; PinosConnection *conn = impl->proxy.conn;
@ -1244,6 +1240,14 @@ on_transport_changed (PinosListener *listener,
pinos_log_error ("client-node %p: error writing connection", this); pinos_log_error ("client-node %p: error writing connection", this);
} }
static void
on_loop_changed (PinosListener *listener,
PinosNode *node)
{
PinosClientNodeImpl *impl = SPA_CONTAINER_OF (listener, PinosClientNodeImpl, loop_changed);
impl->proxy.data_loop = &node->data_loop->poll;
}
static SpaResult static SpaResult
proxy_clear (SpaProxy *this) proxy_clear (SpaProxy *this)
{ {
@ -1257,35 +1261,18 @@ proxy_clear (SpaProxy *this)
if (this->out_ports[i].valid) if (this->out_ports[i].valid)
clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i); clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i);
} }
if (this->fds[0].fd != -1) { if (this->ctrl_fds[0].fd != -1) {
spa_poll_remove_item (this->main_loop, &this->poll); spa_poll_remove_item (this->main_loop, &this->ctrl_poll);
close (this->fds[0].fd); close (this->ctrl_fds[0].fd);
} }
if (this->rtfds[0].fd != -1) { if (this->data_fds[0].fd != -1) {
spa_poll_remove_item (this->data_loop, &this->rtpoll); spa_poll_remove_item (this->data_loop, &this->data_poll);
close (this->rtfds[0].fd); close (this->data_fds[0].fd);
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
static void
client_node_destroy (PinosObject * object)
{
PinosClientNodeImpl *impl = (PinosClientNodeImpl *) object;
PinosClientNode *this = &impl->this;
pinos_log_debug ("client-node %p: destroy", this);
proxy_clear (&impl->proxy);
if (impl->fd != -1)
close (impl->fd);
if (impl->rtfd != -1)
close (impl->rtfd);
free (impl);
}
/** /**
* pinos_client_node_new: * pinos_client_node_new:
* @daemon: a #PinosDaemon * @daemon: a #PinosDaemon
@ -1310,16 +1297,12 @@ pinos_client_node_new (PinosCore *core,
impl = calloc (1, sizeof (PinosClientNodeImpl)); impl = calloc (1, sizeof (PinosClientNodeImpl));
impl->core = core; impl->core = core;
impl->ctrl_fd = -1;
impl->data_fd = -1;
this = &impl->this; this = &impl->this;
pinos_log_debug ("client-node %p: new", impl); pinos_log_debug ("client-node %p: new", impl);
impl->ifaces[0].type = impl->core->registry.uri.node; pinos_signal_init (&this->destroy_signal);
impl->ifaces[0].iface = this;
pinos_object_init (&this->object,
client_node_destroy,
1,
impl->ifaces);
proxy_init (&impl->proxy, NULL, core->support, core->n_support); proxy_init (&impl->proxy, NULL, core->support, core->n_support);
@ -1331,91 +1314,93 @@ pinos_client_node_new (PinosCore *core,
impl->proxy.pnode = this->node; impl->proxy.pnode = this->node;
impl->transport_changed.notify = on_transport_changed; pinos_signal_add (&this->node->transport_changed,
pinos_signal_add (&this->node->transport_changed, &impl->transport_changed); &impl->transport_changed,
on_transport_changed);
pinos_signal_add (&this->node->loop_changed,
&impl->loop_changed,
on_loop_changed);
return this; return this;
} }
void
pinos_client_node_destroy (PinosClientNode * this)
{
PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
pinos_log_debug ("client-node %p: destroy", impl);
pinos_signal_emit (&this->destroy_signal, this);
pinos_node_destroy (this->node);
proxy_clear (&impl->proxy);
if (impl->ctrl_fd != -1)
close (impl->ctrl_fd);
if (impl->data_fd != -1)
close (impl->data_fd);
free (impl);
}
/** /**
* pinos_client_node_get_socket_pair: * pinos_client_node_get_ctrl_socket:
* @node: a #PinosClientNode * @node: a #PinosClientNode
* @error: a #GError * @fd: a result socket
* *
* Create or return a previously create socket pair for @node. The * Create or return a previously create socket pair for @node. The
* Socket for the other end is returned. * socket for the other end is returned.
* *
* Returns: a socket that can be used to send/receive buffers to node. * Returns: %SPA_RESULT_OK on success
*/ */
int SpaResult
pinos_client_node_get_socket_pair (PinosClientNode *this, pinos_client_node_get_ctrl_socket (PinosClientNode *this,
GError **error) int *fd)
{ {
PinosClientNodeImpl *impl = (PinosClientNodeImpl *) this; PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
g_return_val_if_fail (this, -1); if (impl->ctrl_fd == -1) {
if (impl->fd == -1) {
int fd[2]; int fd[2];
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0) if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0)
goto no_sockets; return SPA_RESULT_ERRNO;
impl->proxy.fds[0].fd = fd[0]; impl->proxy.ctrl_fds[0].fd = fd[0];
impl->proxy.conn = pinos_connection_new (impl->proxy.fds[0].fd); impl->proxy.conn = pinos_connection_new (impl->proxy.ctrl_fds[0].fd);
spa_poll_add_item (impl->proxy.main_loop, &impl->proxy.poll); spa_poll_add_item (impl->proxy.main_loop, &impl->proxy.ctrl_poll);
impl->fd = fd[1]; impl->ctrl_fd = fd[1];
}
return impl->fd;
/* ERRORS */
no_sockets:
{
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errno),
"could not create socketpair: %s", strerror (errno));
return -1;
} }
*fd = impl->ctrl_fd;
return SPA_RESULT_OK;
} }
/** /**
* pinos_client_node_get_rtsocket_pair: * pinos_client_node_get_data_socket:
* @node: a #PinosClientNode * @node: a #PinosClientNode
* @error: a #GError * @error: a #GError
* *
* Create or return a previously create socket pair for @node. The * Create or return a previously create socket pair for @node. The
* Socket for the other end is returned. * Socket for the other end is returned.
* *
* Returns: a #GSocket that can be used to send/receive buffers to node. * Returns: %SPA_RESULT_OK on success
*/ */
int SpaResult
pinos_client_node_get_rtsocket_pair (PinosClientNode *this, pinos_client_node_get_data_socket (PinosClientNode *this,
GError **error) int *fd)
{ {
PinosClientNodeImpl *impl = (PinosClientNodeImpl *) this; PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
g_return_val_if_fail (this, -1); if (impl->data_fd == -1) {
if (impl->fd == -1) {
int fd[2]; int fd[2];
if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0) if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0)
goto no_sockets; return SPA_RESULT_ERRNO;
impl->proxy.rtfds[0].fd = fd[0]; impl->proxy.data_fds[0].fd = fd[0];
spa_poll_add_item (impl->proxy.data_loop, &impl->proxy.rtpoll); spa_poll_add_item (impl->proxy.data_loop, &impl->proxy.data_poll);
impl->rtfd = fd[1]; impl->data_fd = fd[1];
}
return impl->rtfd;
/* ERRORS */
no_sockets:
{
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errno),
"could not create socketpair: %s", strerror (errno));
return -1;
} }
*fd = impl->data_fd;
return SPA_RESULT_OK;
} }

View file

@ -20,14 +20,11 @@
#ifndef __PINOS_CLIENT_NODE_H__ #ifndef __PINOS_CLIENT_NODE_H__
#define __PINOS_CLIENT_NODE_H__ #define __PINOS_CLIENT_NODE_H__
#include <glib-object.h>
#include <pinos/server/node.h> #include <pinos/server/node.h>
G_BEGIN_DECLS #ifdef __cplusplus
extern "C" {
#define PINOS_CLIENT_NODE_URI "http://pinos.org/ns/client-node" #endif
#define PINOS_CLIENT_NODE_PREFIX PINOS_CLIENT_NODE_URI "#"
typedef struct _PinosClientNode PinosClientNode; typedef struct _PinosClientNode PinosClientNode;
@ -39,20 +36,21 @@ typedef struct _PinosClientNode PinosClientNode;
struct _PinosClientNode { struct _PinosClientNode {
PinosNode *node; PinosNode *node;
int (*get_ctrl_socket) (PinosClientNode *node, PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
GError **error); PinosClientNode *node));
int (*get_data_socket) (PinosClientNode *node,
GError **error);
}; };
PinosObject * pinos_client_node_new (PinosCore *core, PinosClientNode * pinos_client_node_new (PinosCore *core,
PinosClient *client, PinosClient *client,
const gchar *name, const gchar *name,
PinosProperties *properties); PinosProperties *properties);
void pinos_client_node_destroy (PinosClientNode *node);
#define pinos_client_node_get_ctrl_socket(n) (n)->get_ctrl_socket(n,__VA_ARGS__) SpaResult pinos_client_node_get_ctrl_socket (PinosClientNode *node, int *fd);
#define pinos_client_node_get_data_socket(n) (n)->get_data_socket(n,__VA_ARGS__) SpaResult pinos_client_node_get_data_socket (PinosClientNode *node, int *fd);
G_END_DECLS #ifdef __cplusplus
}
#endif
#endif /* __PINOS_CLIENT_NODE_H__ */ #endif /* __PINOS_CLIENT_NODE_H__ */

View file

@ -26,10 +26,7 @@
typedef struct typedef struct
{ {
PinosClient client; PinosClient this;
PinosObject object;
PinosInterface ifaces[1];
PinosDaemon *daemon;
guint id; guint id;
PinosClient1 *iface; PinosClient1 *iface;
@ -45,10 +42,18 @@ client_name_appeared_handler (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
PinosClientImpl *impl = user_data; PinosClientImpl *impl = user_data;
PinosClient *client = &impl->client; PinosClient *this = &impl->this;
PinosObjectSkeleton *skel;
pinos_log_debug ("client %p: appeared %s %s", client, name, name_owner); pinos_log_debug ("client %p: appeared %s %s", this, name, name_owner);
pinos_signal_emit (&client->appeared, client, NULL);
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_CLIENT);
pinos_object_skeleton_set_client1 (skel, impl->iface);
this->global = pinos_core_add_global (this->core,
this->core->registry.uri.client,
this,
skel);
} }
static void static void
@ -57,24 +62,24 @@ client_name_vanished_handler (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
PinosClientImpl *impl = user_data; PinosClientImpl *impl = user_data;
PinosClient *client = &impl->client; PinosClient *this = &impl->this;
pinos_log_debug ("client %p: vanished %s", client, name); pinos_log_debug ("client %p: vanished %s", this, name);
pinos_core_remove_global (this->core,
this->global);
this->global = NULL;
pinos_signal_emit (&client->vanished, client, NULL);
g_bus_unwatch_name (impl->id); g_bus_unwatch_name (impl->id);
} }
static void static void
client_watch_name (PinosClient *client) client_watch_name (PinosClient *this)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (this, PinosClientImpl, this);
GDBusConnection *connection = NULL;
// g_object_get (impl->daemon, "connection", &connection, NULL); impl->id = g_bus_watch_name_on_connection (this->core->connection,
this->sender,
impl->id = g_bus_watch_name_on_connection (connection,
client->sender,
G_BUS_NAME_WATCHER_FLAGS_NONE, G_BUS_NAME_WATCHER_FLAGS_NONE,
client_name_appeared_handler, client_name_appeared_handler,
client_name_vanished_handler, client_name_vanished_handler,
@ -82,65 +87,11 @@ client_watch_name (PinosClient *client)
(GDestroyNotify) pinos_client_destroy); (GDestroyNotify) pinos_client_destroy);
} }
static void void
client_register_object (PinosClient *client) pinos_client_add_object (PinosClient *client,
{
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client);
PinosDaemon *daemon = impl->daemon;
PinosObjectSkeleton *skel;
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_CLIENT);
pinos_object_skeleton_set_client1 (skel, impl->iface);
g_free (impl->object_path);
impl->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
pinos_log_debug ("client %p: register %s", client, impl->object_path);
}
static void
client_unregister_object (PinosClient *client)
{
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client);
PinosDaemon *daemon = impl->daemon;
pinos_log_debug ("client %p: unregister", client);
pinos_daemon_unexport (daemon, impl->object_path);
}
static void
client_destroy (PinosObject * object)
{
PinosClientImpl *impl = SPA_CONTAINER_OF (object, PinosClientImpl, object);
PinosClient *client = &impl->client;
GList *copy;
pinos_log_debug ("client %p: destroy", client);
pinos_registry_remove_object (&client->core->registry, &impl->object);
copy = g_list_copy (impl->objects);
g_list_free_full (copy, NULL);
g_list_free (impl->objects);
client_unregister_object (client);
free (client->sender);
if (client->properties)
pinos_properties_free (client->properties);
g_clear_object (&impl->iface);
free (impl->object_path);
free (object);
}
static void
client_add_object (PinosClient *client,
PinosObject *object) PinosObject *object)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
g_return_if_fail (client); g_return_if_fail (client);
g_return_if_fail (object); g_return_if_fail (object);
@ -148,11 +99,11 @@ client_add_object (PinosClient *client,
impl->objects = g_list_prepend (impl->objects, object); impl->objects = g_list_prepend (impl->objects, object);
} }
static void void
client_remove_object (PinosClient *client, pinos_client_remove_object (PinosClient *client,
PinosObject *object) PinosObject *object)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
g_return_if_fail (client); g_return_if_fail (client);
g_return_if_fail (object); g_return_if_fail (object);
@ -161,11 +112,11 @@ client_remove_object (PinosClient *client,
pinos_object_destroy (object); pinos_object_destroy (object);
} }
static bool bool
client_has_object (PinosClient *client, pinos_client_has_object (PinosClient *client,
PinosObject *object) PinosObject *object)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
GList *found; GList *found;
g_return_val_if_fail (client, false); g_return_val_if_fail (client, false);
@ -192,36 +143,26 @@ pinos_client_new (PinosCore *core,
const gchar *sender, const gchar *sender,
PinosProperties *properties) PinosProperties *properties)
{ {
PinosClient *client; PinosClient *this;
PinosClientImpl *impl; PinosClientImpl *impl;
impl = calloc (1, sizeof (PinosClientImpl *)); impl = calloc (1, sizeof (PinosClientImpl));
client = &impl->client;
client->core = core;
client->sender = strdup (sender);
client->properties = properties;
client->add_object = client_add_object;
client->remove_object = client_remove_object;
client->has_object = client_has_object;
impl->ifaces[0].type = client->core->registry.uri.client;
impl->ifaces[0].iface = client;
pinos_object_init (&impl->object,
client_destroy,
1,
impl->ifaces);
pinos_log_debug ("client %p: new", impl); pinos_log_debug ("client %p: new", impl);
this = &impl->this;
this->core = core;
this->sender = strdup (sender);
this->properties = properties;
pinos_signal_init (&this->destroy_signal);
impl->iface = pinos_client1_skeleton_new (); impl->iface = pinos_client1_skeleton_new ();
client_watch_name (client); client_watch_name (this);
client_register_object (client);
pinos_registry_add_object (&client->core->registry, &impl->object); spa_list_insert (core->client_list.prev, &this->list);
return client; return this;
} }
/** /**
@ -231,14 +172,27 @@ pinos_client_new (PinosCore *core,
* Trigger removal of @client * Trigger removal of @client
*/ */
void void
pinos_client_destroy (PinosClient *client) pinos_client_destroy (PinosClient * client)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
GList *copy;
g_return_if_fail (client);
pinos_log_debug ("client %p: destroy", client); pinos_log_debug ("client %p: destroy", client);
pinos_object_destroy (&impl->object); pinos_signal_emit (&client->destroy_signal, client);
spa_list_remove (&client->list);
copy = g_list_copy (impl->objects);
g_list_free_full (copy, NULL);
g_list_free (impl->objects);
free (client->sender);
if (client->properties)
pinos_properties_free (client->properties);
g_clear_object (&impl->iface);
free (impl->object_path);
free (impl);
} }
/** /**
@ -252,7 +206,7 @@ pinos_client_destroy (PinosClient *client)
const gchar * const gchar *
pinos_client_get_object_path (PinosClient *client) pinos_client_get_object_path (PinosClient *client)
{ {
PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client); PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
g_return_val_if_fail (client, NULL); g_return_val_if_fail (client, NULL);

View file

@ -20,9 +20,9 @@
#ifndef __PINOS_CLIENT_H__ #ifndef __PINOS_CLIENT_H__
#define __PINOS_CLIENT_H__ #define __PINOS_CLIENT_H__
#include <glib-object.h> #ifdef __cplusplus
extern "C" {
G_BEGIN_DECLS #endif
#define PINOS_CLIENT_URI "http://pinos.org/ns/client" #define PINOS_CLIENT_URI "http://pinos.org/ns/client"
#define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#" #define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#"
@ -39,32 +39,33 @@ typedef struct _PinosClient PinosClient;
*/ */
struct _PinosClient { struct _PinosClient {
PinosCore *core; PinosCore *core;
SpaList list;
PinosGlobal *global;
char *sender; char *sender;
PinosProperties *properties; PinosProperties *properties;
PinosSignal appeared; PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosSignal vanished; PinosClient *client));
void (*add_object) (PinosClient *client,
PinosObject *object);
void (*remove_object) (PinosClient *client,
PinosObject *object);
bool (*has_object) (PinosClient *client,
PinosObject *object);
}; };
PinosObject * pinos_client_new (PinosCore *core, PinosClient * pinos_client_new (PinosCore *core,
const gchar *sender, const gchar *sender,
PinosProperties *properties); PinosProperties *properties);
void pinos_client_destroy (PinosClient *client);
const gchar * pinos_client_get_object_path (PinosClient *client); const gchar * pinos_client_get_object_path (PinosClient *client);
#define pinos_client_add_object(c,...) (c)->add_object ((c),__VA_ARGS__)
#define pinos_client_remove_object(c,...) (c)->remove_object ((c),__VA_ARGS__)
#define pinos_client_has_object(c,...) (c)->has_object ((c),__VA_ARGS__)
G_END_DECLS void pinos_client_add_object (PinosClient *client,
PinosObject *object);
void pinos_client_remove_object (PinosClient *client,
PinosObject *object);
bool pinos_client_has_object (PinosClient *client,
PinosObject *object);
#ifdef __cplusplus
}
#endif
#endif /* __PINOS_CLIENT_H__ */ #endif /* __PINOS_CLIENT_H__ */

View file

@ -18,46 +18,36 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include <glib.h>
#include <string.h> #include <string.h>
#include <pinos/client/pinos.h> #include <pinos/client/pinos.h>
#include <pinos/client/utils.h>
#include <pinos/server/module.h> #include <pinos/server/module.h>
#include "command.h" #include "command.h"
GQuark typedef bool (*PinosCommandFunc) (PinosCommand *command,
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,
PinosCore *core, PinosCore *core,
GError **err); char **err);
static gboolean execute_command_module_load (PinosCommand *command, static bool execute_command_module_load (PinosCommand *command,
PinosCore *core, PinosCore *core,
GError **err); char **err);
typedef PinosCommand * (*PinosCommandParseFunc) (const gchar *line, typedef PinosCommand * (*PinosCommandParseFunc) (const gchar *line,
GError **err); char **err);
static PinosCommand * parse_command_module_load (const gchar *line, static PinosCommand * parse_command_module_load (const gchar *line,
GError **err); char **err);
struct _PinosCommand typedef struct
{ {
PinosCommand this;
PinosCommandFunc func; PinosCommandFunc func;
gchar **args; char **args;
gint n_args; int n_args;
}; } PinosCommandImpl;
typedef struct _CommandParse typedef struct _CommandParse
{ {
@ -72,84 +62,40 @@ static const CommandParse parsers[] = {
static const gchar whitespace[] = " \t"; 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 * static PinosCommand *
parse_command_module_load (const gchar * line, GError ** err) parse_command_module_load (const char * line, char ** err)
{ {
PinosCommand *command; PinosCommandImpl *impl;
command = g_new0 (PinosCommand, 1); impl = calloc (1, sizeof (PinosCommandImpl));
command->func = execute_command_module_load; impl->func = execute_command_module_load;
command->args = tokenize (line, 3, &command->n_args); impl->args = pinos_split_strv (line, whitespace, 3, &impl->n_args);
if (command->args[1] == NULL) if (impl->args[1] == NULL)
goto no_module; goto no_module;
return command; impl->this.name = impl->args[0];
return &impl->this;
no_module: no_module:
g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_PARSE, asprintf (err, "%s requires a module name", impl->args[0]);
"%s requires a module name", command->args[0]); pinos_free_strv (impl->args);
g_strfreev (command->args);
return NULL; return NULL;
} }
static gboolean static bool
execute_command_module_load (PinosCommand *command, execute_command_module_load (PinosCommand *command,
PinosCore *core, PinosCore *core,
GError **err) char **err)
{ {
gchar *module; PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
gchar *args;
module = command->args[1]; return pinos_module_load (core,
args = command->args[2]; impl->args[1],
impl->args[2],
return pinos_module_load (core, module, args, err) != NULL; err) != NULL;
} }
/** /**
@ -161,57 +107,47 @@ execute_command_module_load (PinosCommand *command,
void void
pinos_command_free (PinosCommand * command) pinos_command_free (PinosCommand * command)
{ {
g_return_if_fail (command != NULL); PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
g_strfreev (command->args); spa_list_remove (&command->link);
pinos_free_strv (impl->args);
g_free (command); free (impl);
} }
/** /**
* pinos_command_parse: * pinos_command_parse:
* @command: (out): Return location for a #PinosCommand
* @line: command line to parse * @line: command line to parse
* @err: Return location for a #GError, or %NULL * @err: Return location for an error
* *
* Parses a command line, @line, and store the parsed command in @command. * Parses a command line, @line, and return the parsed command.
* A command can later be executed with pinos_command_run(). * A command can later be executed with pinos_command_run().
* *
* Returns: %TRUE on success, %FALSE otherwise. * Returns: The command or %NULL when @err is set.
*/ */
gboolean PinosCommand *
pinos_command_parse (PinosCommand ** command, pinos_command_parse (const char *line,
gchar * line, char **err)
GError ** err)
{ {
PinosCommand *command = NULL;
const CommandParse *parse; const CommandParse *parse;
gchar *name; gchar *name;
gsize len; 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); len = strcspn (line, whitespace);
name = g_strndup (line, len); name = strndup (line, len);
for (parse = parsers; parse->name != NULL; parse++) { for (parse = parsers; parse->name != NULL; parse++) {
if (g_strcmp0 (name, parse->name) == 0) { if (strcmp (name, parse->name) == 0) {
*command = parse->func (line, err); command = parse->func (line, err);
if (*command != NULL)
ret = TRUE;
goto out; goto out;
} }
} }
g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_NO_SUCH_COMMAND, asprintf (err, "Command \"%s\" does not exist", name);
"Command \"%s\" does not exist", name);
out: out:
g_free (name); free (name);
return command;
return ret;
} }
/** /**
@ -222,17 +158,16 @@ out:
* *
* Run @command. * Run @command.
* *
* Returns: %TRUE if @command was executed successfully, %FALSE otherwise. * Returns: %true if @command was executed successfully, %false otherwise.
*/ */
gboolean bool
pinos_command_run (PinosCommand *command, pinos_command_run (PinosCommand *command,
PinosCore *core, PinosCore *core,
GError **err) char **err)
{ {
g_return_val_if_fail (command != NULL, FALSE); PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
g_return_val_if_fail (core, FALSE);
return command->func (command, core, err); return impl->func (command, core, err);
} }
/** /**
@ -243,10 +178,10 @@ pinos_command_run (PinosCommand *command,
* *
* Returns: The name of @command. * Returns: The name of @command.
*/ */
const gchar * const char *
pinos_command_get_name (PinosCommand * command) pinos_command_get_name (PinosCommand * command)
{ {
g_return_val_if_fail (command != NULL, NULL); PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
return command->args[0]; return impl->args[0];
} }

View file

@ -21,49 +21,30 @@
#ifndef __PINOS_COMMAND_H__ #ifndef __PINOS_COMMAND_H__
#define __PINOS_COMMAND_H__ #define __PINOS_COMMAND_H__
#include <glib.h> #ifdef __cplusplus
extern "C" {
G_BEGIN_DECLS #endif
#include <pinos/server/daemon.h> #include <pinos/server/daemon.h>
typedef struct _PinosCommand PinosCommand; typedef struct _PinosCommand PinosCommand;
GQuark pinos_command_error_quark (void);
/**
* PINOS_COMMAND_ERROR:
*
* Pinos command error.
*/
#define PINOS_COMMAND_ERROR (pinos_command_error_quark ())
/** struct _PinosCommand {
* PinosCommandError: SpaList link;
* @PINOS_COMMAND_ERROR_GENERIC: Generic command error.
* @PINOS_COMMAND_ERROR_NO_SUCH_COMMAND: No such command. const char *name;
* @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); void pinos_command_free (PinosCommand *command);
gboolean pinos_command_parse (PinosCommand **command, PinosCommand * pinos_command_parse (const char *line,
gchar *line, char **err);
GError **err); bool pinos_command_run (PinosCommand *command,
gboolean pinos_command_run (PinosCommand *command,
PinosCore *core, PinosCore *core,
GError **err); char **err);
const gchar * pinos_command_get_name (PinosCommand *command); #ifdef __cplusplus
}
G_END_DECLS #endif
#endif /* __PINOS_COMMAND_H__ */ #endif /* __PINOS_COMMAND_H__ */

View file

@ -21,46 +21,93 @@
#include <pinos/server/data-loop.h> #include <pinos/server/data-loop.h>
typedef struct { typedef struct {
PinosCore object; PinosCore this;
PinosDataLoop *data_loop; GDBusObjectManagerServer *server_manager;
SpaSupport support[4]; SpaSupport support[4];
} PinosCoreImpl; } PinosCoreImpl;
static void
core_destroy (PinosObject *object)
{
free (object);
}
PinosCore * PinosCore *
pinos_core_new (PinosMainLoop *main_loop) pinos_core_new (PinosMainLoop *main_loop)
{ {
PinosCoreImpl *impl; PinosCoreImpl *impl;
PinosCore *this;
impl = calloc (1, sizeof (PinosCoreImpl)); impl = calloc (1, sizeof (PinosCoreImpl));
pinos_registry_init (&impl->object.registry); this = &impl->this;
pinos_registry_init (&this->registry);
pinos_object_init (&impl->object.object, this->data_loop = pinos_data_loop_new ();
impl->object.registry.uri.core, this->main_loop = main_loop;
impl,
core_destroy);
impl->data_loop = pinos_data_loop_new ();
impl->object.main_loop = main_loop;
impl->support[0].uri = SPA_ID_MAP_URI; impl->support[0].uri = SPA_ID_MAP_URI;
impl->support[0].data = impl->object.registry.map; impl->support[0].data = this->registry.map;
impl->support[1].uri = SPA_LOG_URI; impl->support[1].uri = SPA_LOG_URI;
impl->support[1].data = pinos_log_get (); impl->support[1].data = pinos_log_get ();
impl->support[2].uri = SPA_POLL__DataLoop; impl->support[2].uri = SPA_POLL__DataLoop;
impl->support[2].data = &impl->data_loop->poll; impl->support[2].data = &this->data_loop->poll;
impl->support[3].uri = SPA_POLL__MainLoop; impl->support[3].uri = SPA_POLL__MainLoop;
impl->support[3].data = &impl->object.main_loop->poll; impl->support[3].data = this->main_loop->poll;
impl->object.support = impl->support; this->support = impl->support;
impl->object.n_support = 4; this->n_support = 4;
return &impl->object; spa_list_init (&this->global_list);
spa_list_init (&this->client_list);
spa_list_init (&this->node_list);
spa_list_init (&this->link_list);
pinos_signal_init (&this->destroy_signal);
pinos_signal_init (&this->global_added);
pinos_signal_init (&this->global_removed);
pinos_signal_init (&this->node_state_changed);
pinos_signal_init (&this->port_added);
pinos_signal_init (&this->port_removed);
pinos_signal_init (&this->port_unlinked);
pinos_signal_init (&this->link_state_changed);
return this;
}
void
pinos_core_destroy (PinosCore *core)
{
PinosCoreImpl *impl = SPA_CONTAINER_OF (core, PinosCoreImpl, this);
pinos_signal_emit (&core->destroy_signal, core);
pinos_data_loop_destroy (core->data_loop);
free (impl);
}
PinosGlobal *
pinos_core_add_global (PinosCore *core,
uint32_t type,
void *object,
PinosObjectSkeleton *skel)
{
PinosGlobal *global;
global = calloc (1, sizeof (PinosGlobal));
global->core = core;
global->id = 0;
global->type = type;
global->object = object;
global->skel = skel;
spa_list_insert (core->global_list.prev, &global->list);
pinos_signal_emit (&core->global_added, core, global);
return global;
}
void
pinos_core_remove_global (PinosCore *core,
PinosGlobal *global)
{
pinos_signal_emit (&core->global_removed, core, global);
spa_list_remove (&global->list);
free (global);
} }

View file

@ -24,14 +24,30 @@
extern "C" { extern "C" {
#endif #endif
#define PINOS_CORE_URI "http://pinos.org/ns/core"
#define PINOS_CORE_PREFIX PINOS_CORE_URI "#"
typedef struct _PinosCore PinosCore; typedef struct _PinosCore PinosCore;
typedef struct _PinosGlobal PinosGlobal;
#include <gio/gio.h>
#include <spa/include/spa/log.h> #include <spa/include/spa/log.h>
#include <pinos/server/main-loop.h> #include <pinos/server/main-loop.h>
#include <pinos/server/data-loop.h>
#include <pinos/server/registry.h> #include <pinos/server/registry.h>
#include <pinos/server/node.h>
#include <pinos/server/link.h>
#include "pinos/dbus/org-pinos.h"
struct _PinosGlobal {
PinosCore *core;
SpaList list;
uint32_t id;
uint32_t type;
void *object;
PinosObjectSkeleton *skel;
const char *object_path;
};
/** /**
* PinosCore: * PinosCore:
@ -39,17 +55,61 @@ typedef struct _PinosCore PinosCore;
* Pinos core object class. * Pinos core object class.
*/ */
struct _PinosCore { struct _PinosCore {
PinosObject object;
PinosRegistry registry; PinosRegistry registry;
GDBusConnection *connection;
SpaList global_list;
SpaList client_list;
SpaList node_list;
SpaList link_list;
PinosMainLoop *main_loop; PinosMainLoop *main_loop;
PinosDataLoop *data_loop;
SpaSupport *support; SpaSupport *support;
unsigned int n_support; unsigned int n_support;
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosCore *core));
PINOS_SIGNAL (global_added, (PinosListener *listener,
PinosCore *core,
PinosGlobal *global));
PINOS_SIGNAL (global_removed, (PinosListener *listener,
PinosCore *core,
PinosGlobal *global));
PINOS_SIGNAL (node_state_changed, (PinosListener *listener,
PinosNode *object,
PinosNodeState old,
PinosNodeState state));
PINOS_SIGNAL (port_added, (PinosListener *listener,
PinosNode *node,
PinosPort *port));
PINOS_SIGNAL (port_removed, (PinosListener *listener,
PinosNode *node,
PinosPort *port));
PINOS_SIGNAL (port_unlinked, (PinosListener *listener,
PinosLink *link,
PinosPort *port));
PINOS_SIGNAL (link_state_changed, (PinosListener *listener,
PinosLink *link));
}; };
PinosCore * pinos_core_new (PinosMainLoop *main_loop); PinosCore * pinos_core_new (PinosMainLoop *main_loop);
void pinos_core_destroy (PinosCore *core);
PinosGlobal * pinos_core_add_global (PinosCore *core,
uint32_t type,
void *object,
PinosObjectSkeleton *skel);
void pinos_core_remove_global (PinosCore *core,
PinosGlobal *global);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -19,6 +19,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixfdlist.h> #include <gio/gunixfdlist.h>
@ -40,22 +41,20 @@
#include "pinos/dbus/org-pinos.h" #include "pinos/dbus/org-pinos.h"
typedef struct { typedef struct {
PinosDaemon daemon; PinosDaemon this;
PinosObject object;
GDBusObjectManagerServer *server_manager;
PinosDaemon1 *iface; PinosDaemon1 *iface;
guint id; guint id;
GDBusConnection *connection;
GDBusObjectManagerServer *server_manager;
gchar *object_path; PinosListener global_added;
PinosListener global_removed;
PinosDataLoop *data_loop; PinosListener port_added;
PinosListener port_removed;
PinosListener object_added;
PinosListener object_removed;
PinosListener port_unlinked; PinosListener port_unlinked;
PinosListener notify_state; PinosListener node_state_changed;
PinosListener link_state_changed;
GHashTable *clients; GHashTable *clients;
GHashTable *node_factories; GHashTable *node_factories;
@ -63,60 +62,21 @@ typedef struct {
static void try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *daemon); static void try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *daemon);
static void
handle_client_appeared (PinosClient *client, gpointer user_data)
{
PinosDaemonImpl *impl = user_data;
pinos_log_debug ("daemon %p: appeared %p", impl, client);
g_hash_table_insert (impl->clients, (gpointer) client->sender, client);
}
static void
handle_client_vanished (PinosClient *client, gpointer user_data)
{
PinosDaemonImpl *impl = user_data;
pinos_log_debug ("daemon %p: vanished %p", daemon, client);
g_hash_table_remove (impl->clients, (gpointer) client->sender);
}
static PinosClient * static PinosClient *
sender_get_client (PinosDaemon *daemon, sender_get_client (PinosDaemon *daemon,
const gchar *sender, const gchar *sender,
gboolean create) gboolean create)
{ {
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon; PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
PinosClient *client; PinosClient *client;
client = g_hash_table_lookup (impl->clients, sender); client = g_hash_table_lookup (impl->clients, sender);
if (client == NULL && create) { if (client == NULL && create) {
client = pinos_client_new (daemon->core, sender, NULL); client = pinos_client_new (daemon->core, sender, NULL);
pinos_log_debug ("daemon %p: new client %p for %s", daemon, client, sender);
g_signal_connect (client,
"appeared",
(GCallback) handle_client_appeared,
daemon);
g_signal_connect (client,
"vanished",
(GCallback) handle_client_vanished,
daemon);
} }
return client; return client;
} }
static void
handle_remove_node (PinosNode *node,
gpointer user_data)
{
//PinosClient *client = user_data;
//pinos_log_debug ("client %p: node %p remove", daemon, node);
//pinos_client_remove_object (client, &node->object);
}
static gboolean static gboolean
handle_create_node (PinosDaemon1 *interface, handle_create_node (PinosDaemon1 *interface,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@ -126,6 +86,7 @@ handle_create_node (PinosDaemon1 *interface,
gpointer user_data) gpointer user_data)
{ {
PinosDaemonImpl *impl = user_data; PinosDaemonImpl *impl = user_data;
PinosDaemon *this = &impl->this;
PinosNodeFactory *factory; PinosNodeFactory *factory;
PinosNode *node; PinosNode *node;
PinosClient *client; PinosClient *client;
@ -133,7 +94,7 @@ handle_create_node (PinosDaemon1 *interface,
PinosProperties *props; PinosProperties *props;
sender = g_dbus_method_invocation_get_sender (invocation); sender = g_dbus_method_invocation_get_sender (invocation);
client = sender_get_client (&impl->daemon, sender, TRUE); client = sender_get_client (this, sender, TRUE);
pinos_log_debug ("daemon %p: create node: %s", impl, sender); pinos_log_debug ("daemon %p: create node: %s", impl, sender);
@ -154,17 +115,10 @@ handle_create_node (PinosDaemon1 *interface,
//pinos_client_add_object (client, &node->object); //pinos_client_add_object (client, &node->object);
//g_signal_connect (node, object_path = node->global->object_path;
// "remove",
// (GCallback) handle_remove_node,
// client);
object_path = pinos_node_get_object_path (node);
pinos_log_debug ("daemon %p: added node %p with path %s", impl, node, object_path); pinos_log_debug ("daemon %p: added node %p with path %s", impl, node, object_path);
g_dbus_method_invocation_return_value (invocation, g_dbus_method_invocation_return_value (invocation,
g_variant_new ("(o)", object_path)); g_variant_new ("(o)", object_path));
g_object_unref (node);
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -187,39 +141,34 @@ no_node:
static void static void
on_link_port_unlinked (PinosListener *listener, on_link_port_unlinked (PinosListener *listener,
void *object, PinosLink *link,
void *data) PinosPort *port)
{ {
PinosLink *link = object;
PinosPort *port = data;
PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, port_unlinked); PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, port_unlinked);
pinos_log_debug ("daemon %p: link %p: port %p unlinked", impl, link, port); pinos_log_debug ("daemon %p: link %p: port %p unlinked", impl, link, port);
if (port->direction == PINOS_DIRECTION_OUTPUT && link->input) if (port->direction == PINOS_DIRECTION_OUTPUT && link->input)
try_link_port (link->input->node, link->input, &impl->daemon); try_link_port (link->input->node, link->input, &impl->this);
} }
static void static void
on_link_notify_state (PinosListener *listener, on_link_state_changed (PinosListener *listener,
void *object, PinosLink *link)
void *data)
{ {
PinosLink *link = object; PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, link_state_changed);
PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, notify_state);
GError *error = NULL;
PinosLinkState state; PinosLinkState state;
state = pinos_link_get_state (link, &error); state = link->state;
switch (state) { switch (state) {
case PINOS_LINK_STATE_ERROR: case PINOS_LINK_STATE_ERROR:
{ {
pinos_log_debug ("daemon %p: link %p: state error: %s", impl, link, error->message); pinos_log_debug ("daemon %p: link %p: state error: %s", impl, link, link->error->message);
if (link->input && link->input->node) if (link->input && link->input->node)
pinos_node_report_error (link->input->node, g_error_copy (error)); pinos_node_report_error (link->input->node, g_error_copy (link->error));
if (link->output && link->output->node) if (link->output && link->output->node)
pinos_node_report_error (link->output->node, g_error_copy (error)); pinos_node_report_error (link->output->node, g_error_copy (link->error));
break; break;
} }
@ -251,10 +200,10 @@ on_link_notify_state (PinosListener *listener,
static void static void
try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this) try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this)
{ {
PinosDaemonImpl *impl = (PinosDaemonImpl *) this; //PinosDaemonImpl *impl = SPA_CONTAINER_OF (this, PinosDaemonImpl, this);
PinosClient *client; //PinosClient *client;
PinosProperties *props; PinosProperties *props;
const gchar *path; const char *path;
GError *error = NULL; GError *error = NULL;
PinosLink *link; PinosLink *link;
@ -284,19 +233,14 @@ try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this)
if (link == NULL) if (link == NULL)
goto error; goto error;
#if 0
client = pinos_node_get_client (node); client = pinos_node_get_client (node);
if (client) if (client)
pinos_client_add_object (client, &link->object); pinos_client_add_object (client, &link->object);
#endif
impl->port_unlinked.notify = on_link_port_unlinked;
pinos_signal_add (&link->port_unlinked, &impl->port_unlinked);
impl->notify_state.notify = on_link_notify_state;
pinos_signal_add (&link->notify_state, &impl->notify_state);
pinos_link_activate (link); pinos_link_activate (link);
g_object_unref (link);
} }
return; return;
@ -308,62 +252,64 @@ error:
} }
static void static void
on_port_added (PinosNode *node, PinosPort *port, PinosDaemon *this) on_port_added (PinosListener *listener,
PinosNode *node,
PinosPort *port)
{ {
try_link_port (node, port, this); PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, port_added);
try_link_port (node, port, &impl->this);
} }
static void static void
on_port_removed (PinosNode *node, PinosPort *port, PinosDaemon *this) on_port_removed (PinosListener *listener,
PinosNode *node,
PinosPort *port)
{ {
} }
static void static void
on_node_created (PinosNode *node, on_node_created (PinosNode *node,
PinosDaemon *this) PinosDaemonImpl *impl)
{ {
GList *ports, *walk; GList *ports, *walk;
ports = pinos_node_get_ports (node, PINOS_DIRECTION_INPUT); ports = pinos_node_get_ports (node, PINOS_DIRECTION_INPUT);
for (walk = ports; walk; walk = g_list_next (walk)) for (walk = ports; walk; walk = g_list_next (walk))
on_port_added (node, walk->data, this); on_port_added (&impl->port_added, node, walk->data);
ports = pinos_node_get_ports (node, PINOS_DIRECTION_OUTPUT); ports = pinos_node_get_ports (node, PINOS_DIRECTION_OUTPUT);
for (walk = ports; walk; walk = g_list_next (walk)) for (walk = ports; walk; walk = g_list_next (walk))
on_port_added (node, walk->data, this); on_port_added (&impl->port_added, node, walk->data);
g_signal_connect (node, "port-added", (GCallback) on_port_added, this);
g_signal_connect (node, "port-removed", (GCallback) on_port_removed, this);
} }
static void static void
on_node_state_change (PinosNode *node, on_node_state_changed (PinosListener *listener,
PinosNode *node,
PinosNodeState old, PinosNodeState old,
PinosNodeState state, PinosNodeState state)
PinosDaemon *this)
{ {
pinos_log_debug ("daemon %p: node %p state change %s -> %s", this, node, PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, node_state_changed);
pinos_log_debug ("daemon %p: node %p state change %s -> %s", impl, node,
pinos_node_state_as_string (old), pinos_node_state_as_string (old),
pinos_node_state_as_string (state)); pinos_node_state_as_string (state));
if (old == PINOS_NODE_STATE_CREATING && state == PINOS_NODE_STATE_SUSPENDED) if (old == PINOS_NODE_STATE_CREATING && state == PINOS_NODE_STATE_SUSPENDED)
on_node_created (node, this); on_node_created (node, impl);
} }
static void static void
on_node_added (PinosDaemon *daemon, PinosNode *node) on_node_added (PinosDaemon *daemon, PinosNode *node)
{ {
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon; PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
pinos_log_debug ("daemon %p: node %p added", impl, node); pinos_log_debug ("daemon %p: node %p added", impl, node);
g_object_set (node, "data-loop", impl->data_loop, NULL); pinos_node_set_data_loop (node, daemon->core->data_loop);
g_signal_connect (node, "state-change", (GCallback) on_node_state_change, impl);
if (node->state > PINOS_NODE_STATE_CREATING) { if (node->state > PINOS_NODE_STATE_CREATING) {
on_node_created (node, daemon); on_node_created (node, impl);
} }
} }
@ -382,18 +328,19 @@ handle_create_client_node (PinosDaemon1 *interface,
gpointer user_data) gpointer user_data)
{ {
PinosDaemonImpl *impl = user_data; PinosDaemonImpl *impl = user_data;
PinosDaemon *this = &impl->daemon; PinosDaemon *this = &impl->this;
PinosClientNode *node; PinosClientNode *node;
PinosClient *client; PinosClient *client;
const gchar *sender, *object_path; SpaResult res;
const char *sender, *object_path;
PinosProperties *props; PinosProperties *props;
GError *error = NULL; GError *error = NULL;
GUnixFDList *fdlist; GUnixFDList *fdlist;
int socket, rtsocket; int ctrl_fd, data_fd;
gint fdidx, rtfdidx; int ctrl_idx, data_idx;
sender = g_dbus_method_invocation_get_sender (invocation); sender = g_dbus_method_invocation_get_sender (invocation);
client = sender_get_client (&impl->daemon, sender, TRUE); client = sender_get_client (this, sender, TRUE);
pinos_log_debug ("daemon %p: create client-node: %s", impl, sender); pinos_log_debug ("daemon %p: create client-node: %s", impl, sender);
props = pinos_properties_from_variant (arg_properties); props = pinos_properties_from_variant (arg_properties);
@ -402,35 +349,32 @@ handle_create_client_node (PinosDaemon1 *interface,
client, client,
arg_name, arg_name,
props); props);
pinos_properties_free (props);
socket = pinos_client_node_get_socket_pair (node, &error); if ((res = pinos_client_node_get_ctrl_socket (node, &ctrl_fd)) < 0)
if (socket == -1)
goto no_socket; goto no_socket;
rtsocket = pinos_client_node_get_rtsocket_pair (node, &error); if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0)
if (rtsocket == -1)
goto no_socket; goto no_socket;
//pinos_client_add_object (client, &node->object); //pinos_client_add_object (client, &node->object);
object_path = pinos_node_get_object_path (node->node); object_path = node->node->global->object_path;
pinos_log_debug ("daemon %p: add client-node %p, %s", impl, node, object_path); pinos_log_debug ("daemon %p: add client-node %p, %s", impl, node, object_path);
fdlist = g_unix_fd_list_new (); fdlist = g_unix_fd_list_new ();
fdidx = g_unix_fd_list_append (fdlist, socket, &error); ctrl_idx = g_unix_fd_list_append (fdlist, ctrl_fd, &error);
rtfdidx = g_unix_fd_list_append (fdlist, rtsocket, &error); data_idx = g_unix_fd_list_append (fdlist, data_fd, &error);
g_dbus_method_invocation_return_value_with_unix_fd_list (invocation, g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
g_variant_new ("(ohh)", object_path, fdidx, rtfdidx), fdlist); g_variant_new ("(ohh)", object_path, ctrl_idx, data_idx), fdlist);
g_object_unref (fdlist); g_object_unref (fdlist);
return TRUE; return TRUE;
no_socket: no_socket:
{ {
pinos_log_debug ("daemon %p: could not create socket %s", impl, error->message); pinos_log_debug ("daemon %p: could not create socket: %s", impl, strerror (errno));
g_object_unref (node); pinos_client_node_destroy (node);
goto exit_error; goto exit_error;
} }
exit_error: exit_error:
@ -441,15 +385,14 @@ exit_error:
} }
} }
#if 0
static void static void
export_server_object (PinosDaemon *daemon, export_server_object (PinosDaemon *daemon,
GDBusObjectManagerServer *manager) GDBusObjectManagerServer *manager)
{ {
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon; PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
PinosObjectSkeleton *skel;
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SERVER); skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SERVER);
pinos_object_skeleton_set_daemon1 (skel, impl->iface); pinos_object_skeleton_set_daemon1 (skel, impl->iface);
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (skel)); g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (skel));
@ -457,6 +400,7 @@ export_server_object (PinosDaemon *daemon,
impl->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel))); impl->object_path = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));
g_object_unref (skel); g_object_unref (skel);
} }
#endif
static void static void
bus_acquired_handler (GDBusConnection *connection, bus_acquired_handler (GDBusConnection *connection,
@ -464,12 +408,10 @@ bus_acquired_handler (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
PinosDaemonImpl *impl = user_data; PinosDaemonImpl *impl = user_data;
PinosDaemon *this = &impl->this;
GDBusObjectManagerServer *manager = impl->server_manager; GDBusObjectManagerServer *manager = impl->server_manager;
impl->connection = connection; this->core->connection = connection;
export_server_object (&impl->daemon, manager);
g_dbus_object_manager_server_set_connection (manager, connection); g_dbus_object_manager_server_set_connection (manager, connection);
} }
@ -486,28 +428,17 @@ name_lost_handler (GDBusConnection *connection,
gpointer user_data) gpointer user_data)
{ {
PinosDaemonImpl *impl = user_data; PinosDaemonImpl *impl = user_data;
PinosDaemon *this = &impl->this;
GDBusObjectManagerServer *manager = impl->server_manager; GDBusObjectManagerServer *manager = impl->server_manager;
g_dbus_object_manager_server_unexport (manager, PINOS_DBUS_OBJECT_SERVER);
g_dbus_object_manager_server_set_connection (manager, connection); g_dbus_object_manager_server_set_connection (manager, connection);
g_clear_pointer (&impl->object_path, g_free); this->core->connection = connection;
impl->connection = connection;
}
const gchar *
pinos_daemon_get_object_path (PinosDaemon *daemon)
{
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon;
g_return_val_if_fail (impl, NULL);
return impl->object_path;
} }
static SpaResult static SpaResult
daemon_start (PinosDaemon *daemon) daemon_start (PinosDaemon *daemon)
{ {
PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, daemon); PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
g_return_val_if_fail (impl, SPA_RESULT_INVALID_ARGUMENTS); g_return_val_if_fail (impl, SPA_RESULT_INVALID_ARGUMENTS);
g_return_val_if_fail (impl->id == 0, SPA_RESULT_INVALID_ARGUMENTS); g_return_val_if_fail (impl->id == 0, SPA_RESULT_INVALID_ARGUMENTS);
@ -529,7 +460,7 @@ daemon_start (PinosDaemon *daemon)
static SpaResult static SpaResult
daemon_stop (PinosDaemon *daemon) daemon_stop (PinosDaemon *daemon)
{ {
PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, daemon); PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
g_return_val_if_fail (impl, SPA_RESULT_INVALID_ARGUMENTS); g_return_val_if_fail (impl, SPA_RESULT_INVALID_ARGUMENTS);
@ -542,90 +473,59 @@ daemon_stop (PinosDaemon *daemon)
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
/**
* pinos_daemon_export_uniquely:
* @daemon: a #PinosDaemon
* @skel: a #GDBusObjectSkeleton
*
* Export @skel with @daemon with a unique name
*
* Returns: the unique named used to export @skel.
*/
gchar *
pinos_daemon_export_uniquely (PinosDaemon *daemon,
GDBusObjectSkeleton *skel)
{
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon;
g_return_val_if_fail (impl, NULL);
g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (skel), NULL);
g_dbus_object_manager_server_export_uniquely (impl->server_manager, skel);
return g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));
}
/**
* pinos_daemon_unexport:
* @daemon: a #PinosDaemon
* @object_path: an object path
*
* Unexport the object on @object_path
*/
void
pinos_daemon_unexport (PinosDaemon *daemon,
const gchar *object_path)
{
PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon;
g_return_if_fail (impl);
g_return_if_fail (g_variant_is_object_path (object_path));
g_dbus_object_manager_server_unexport (impl->server_manager, object_path);
}
static void static void
on_registry_object_added (PinosListener *listener, on_global_added (PinosListener *listener,
void *object, PinosCore *core,
void *data) PinosGlobal *global)
{ {
PinosObject *obj = data; PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, global_added);
PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, object_added); PinosDaemon *this = &impl->this;
PinosDaemon *this = &impl->daemon;
if (obj->type == this->core->registry.uri.node) { if (global->skel) {
PinosNode *node = obj->implementation; g_dbus_object_manager_server_export_uniquely (impl->server_manager,
G_DBUS_OBJECT_SKELETON (global->skel));
global->object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (global->skel));
}
if (global->type == this->core->registry.uri.node) {
PinosNode *node = global->object;
on_node_added (this, node); on_node_added (this, node);
} else if (obj->type == this->core->registry.uri.node_factory) { } else if (global->type == this->core->registry.uri.node_factory) {
PinosNodeFactory *factory = obj->implementation; PinosNodeFactory *factory = global->object;
gchar *name;
g_object_get (factory, "name", &name, NULL); g_hash_table_insert (impl->node_factories, (void *)factory->name, factory);
g_hash_table_insert (impl->node_factories, name, g_object_ref (factory)); } else if (global->type == this->core->registry.uri.client) {
PinosClient *client = global->object;
g_hash_table_insert (impl->clients, (gpointer) client->sender, client);
} }
} }
static void static void
on_registry_object_removed (PinosListener *listener, on_global_removed (PinosListener *listener,
void *object, PinosCore *core,
void *data) PinosGlobal *global)
{ {
PinosObject *obj = data; PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, global_removed);
PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, object_added); PinosDaemon *this = &impl->this;
PinosDaemon *this = &impl->daemon;
if (obj->type == this->core->registry.uri.node) { if (global->object_path) {
PinosNode *node = obj->implementation; g_dbus_object_manager_server_unexport (impl->server_manager, global->object_path);
}
if (global->type == this->core->registry.uri.node) {
PinosNode *node = global->object;
on_node_removed (this, node); on_node_removed (this, node);
} else if (obj->type == this->core->registry.uri.node_factory) { } else if (global->type == this->core->registry.uri.node_factory) {
PinosNodeFactory *factory = obj->implementation; PinosNodeFactory *factory = global->object;
gchar *name;
g_object_get (factory, "name", &name, NULL); g_hash_table_remove (impl->node_factories, factory->name);
g_hash_table_remove (impl->node_factories, name); } else if (global->type == this->core->registry.uri.client) {
g_free (name); PinosClient *client = global->object;
g_hash_table_remove (impl->clients, (gpointer) client->sender);
} }
} }
@ -645,15 +545,14 @@ on_registry_object_removed (PinosListener *listener,
PinosPort * PinosPort *
pinos_daemon_find_port (PinosDaemon *daemon, pinos_daemon_find_port (PinosDaemon *daemon,
PinosPort *other_port, PinosPort *other_port,
const gchar *name, const char *name,
PinosProperties *props, PinosProperties *props,
GPtrArray *format_filters, GPtrArray *format_filters,
GError **error) GError **error)
{ {
PinosPort *best = NULL; PinosPort *best = NULL;
gboolean have_name; gboolean have_name;
void *state = NULL; PinosNode *n;
PinosObject *o;
g_return_val_if_fail (daemon, NULL); g_return_val_if_fail (daemon, NULL);
@ -661,15 +560,11 @@ pinos_daemon_find_port (PinosDaemon *daemon,
pinos_log_debug ("name \"%s\", %d", name, have_name); pinos_log_debug ("name \"%s\", %d", name, have_name);
while ((o = pinos_registry_iterate_nodes (&daemon->core->registry, &state))) { spa_list_for_each (n, &daemon->core->node_list, list) {
PinosNode *n = o->implementation; pinos_log_debug ("node path \"%s\"", n->global->object_path);
if (o->flags & PINOS_OBJECT_FLAG_DESTROYING)
continue;
pinos_log_debug ("node path \"%s\"", pinos_node_get_object_path (n));
if (have_name) { if (have_name) {
if (g_str_has_suffix (pinos_node_get_object_path (n), name)) { if (g_str_has_suffix (n->global->object_path, name)) {
pinos_log_debug ("name \"%s\" matches node %p", name, n); pinos_log_debug ("name \"%s\" matches node %p", name, n);
best = pinos_node_get_free_port (n, pinos_direction_reverse (other_port->direction)); best = pinos_node_get_free_port (n, pinos_direction_reverse (other_port->direction));
@ -688,36 +583,6 @@ pinos_daemon_find_port (PinosDaemon *daemon,
return best; return best;
} }
static void
daemon_destroy (PinosObject *object)
{
PinosDaemonImpl *impl = SPA_CONTAINER_OF (object, PinosDaemonImpl, object);
PinosDaemon *this = &impl->daemon;
pinos_log_debug ("daemon %p: destroy", impl);
pinos_daemon_stop (this);
pinos_signal_remove (&impl->object_added);
pinos_signal_remove (&impl->object_removed);
g_clear_object (&impl->server_manager);
g_clear_object (&impl->iface);
g_hash_table_unref (impl->clients);
g_hash_table_unref (impl->node_factories);
pinos_registry_remove_object (&this->core->registry, &impl->object);
free (impl);
}
void
pinos_daemon_destroy (PinosDaemon *daemon)
{
PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, daemon);
pinos_object_destroy (&impl->object);
}
/** /**
* pinos_daemon_new: * pinos_daemon_new:
* @core: #PinosCore * @core: #PinosCore
@ -733,9 +598,10 @@ pinos_daemon_new (PinosCore *core,
{ {
PinosDaemonImpl *impl; PinosDaemonImpl *impl;
PinosDaemon *this; PinosDaemon *this;
PinosObjectSkeleton *skel;
impl = calloc (1, sizeof (PinosDaemonImpl)); impl = calloc (1, sizeof (PinosDaemonImpl));
this = &impl->daemon; this = &impl->this;
pinos_log_debug ("daemon %p: new", impl); pinos_log_debug ("daemon %p: new", impl);
this->core = core; this->core = core;
@ -744,27 +610,29 @@ pinos_daemon_new (PinosCore *core,
this->start = daemon_start; this->start = daemon_start;
this->stop = daemon_stop; this->stop = daemon_stop;
pinos_object_init (&impl->object, pinos_signal_init (&this->destroy_signal);
core->registry.uri.daemon,
impl,
daemon_destroy);
impl->object_added.notify = on_registry_object_added; pinos_signal_add (&core->global_added, &impl->global_added, on_global_added);
pinos_signal_add (&core->registry.object_added, &impl->object_added); pinos_signal_add (&core->global_removed, &impl->global_removed, on_global_removed);
pinos_signal_add (&core->node_state_changed, &impl->node_state_changed, on_node_state_changed);
impl->object_removed.notify = on_registry_object_removed; pinos_signal_add (&core->port_added, &impl->port_added, on_port_added);
pinos_signal_add (&core->registry.object_removed, &impl->object_removed); pinos_signal_add (&core->port_removed, &impl->port_removed, on_port_removed);
pinos_signal_add (&core->port_unlinked, &impl->port_unlinked, on_link_port_unlinked);
pinos_signal_add (&core->link_state_changed, &impl->link_state_changed, on_link_state_changed);
impl->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX); impl->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX);
impl->clients = g_hash_table_new (g_str_hash, g_str_equal); impl->clients = g_hash_table_new (g_str_hash, g_str_equal);
impl->node_factories = g_hash_table_new_full (g_str_hash, impl->node_factories = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, NULL,
g_object_unref); NULL);
impl->iface = pinos_daemon1_skeleton_new (); impl->iface = pinos_daemon1_skeleton_new ();
g_signal_connect (impl->iface, "handle-create-node", (GCallback) handle_create_node, daemon); g_signal_connect (impl->iface, "handle-create-node", (GCallback) handle_create_node, impl);
g_signal_connect (impl->iface, "handle-create-client-node", (GCallback) handle_create_client_node, daemon); g_signal_connect (impl->iface, "handle-create-client-node", (GCallback) handle_create_client_node, impl);
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SERVER);
pinos_object_skeleton_set_daemon1 (skel, impl->iface);
pinos_daemon1_set_user_name (impl->iface, g_get_user_name ()); pinos_daemon1_set_user_name (impl->iface, g_get_user_name ());
pinos_daemon1_set_host_name (impl->iface, g_get_host_name ()); pinos_daemon1_set_host_name (impl->iface, g_get_host_name ());
@ -773,7 +641,32 @@ pinos_daemon_new (PinosCore *core,
pinos_daemon1_set_cookie (impl->iface, g_random_int()); pinos_daemon1_set_cookie (impl->iface, g_random_int());
pinos_daemon1_set_properties (impl->iface, pinos_properties_to_variant (this->properties)); pinos_daemon1_set_properties (impl->iface, pinos_properties_to_variant (this->properties));
pinos_registry_add_object (&core->registry, &impl->object); this->global = pinos_core_add_global (core,
core->registry.uri.daemon,
this,
skel);
return this; return this;
} }
void
pinos_daemon_destroy (PinosDaemon *daemon)
{
PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
pinos_log_debug ("daemon %p: destroy", impl);
pinos_signal_emit (&daemon->destroy_signal, daemon);
pinos_daemon_stop (daemon);
pinos_signal_remove (&impl->global_added);
pinos_signal_remove (&impl->global_removed);
g_clear_object (&impl->server_manager);
g_clear_object (&impl->iface);
g_hash_table_unref (impl->clients);
g_hash_table_unref (impl->node_factories);
free (impl);
}

View file

@ -39,25 +39,27 @@ typedef struct _PinosDaemon PinosDaemon;
* Pinos daemon object class. * Pinos daemon object class.
*/ */
struct _PinosDaemon { struct _PinosDaemon {
PinosCore *core;
SpaList list;
PinosGlobal *global;
PinosProperties *properties; PinosProperties *properties;
PinosCore *core; PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosDaemon *daemon));
SpaResult (*start) (PinosDaemon *daemon); SpaResult (*start) (PinosDaemon *daemon);
SpaResult (*stop) (PinosDaemon *daemon); SpaResult (*stop) (PinosDaemon *daemon);
}; };
PinosObject * pinos_daemon_new (PinosCore *core, PinosDaemon * pinos_daemon_new (PinosCore *core,
PinosProperties *properties); PinosProperties *properties);
void pinos_daemon_destroy (PinosDaemon *daemon);
const char * pinos_daemon_get_object_path (PinosDaemon *daemon);
#define pinos_daemon_start(d) (d)->start(d) #define pinos_daemon_start(d) (d)->start(d)
#define pinos_daemon_stop(d) (d)->stop(d) #define pinos_daemon_stop(d) (d)->stop(d)
char * pinos_daemon_export_uniquely (PinosDaemon *daemon, GDBusObjectSkeleton *skel);
void pinos_daemon_unexport (PinosDaemon *daemon, const char *name);
PinosPort * pinos_daemon_find_port (PinosDaemon *daemon, PinosPort * pinos_daemon_find_port (PinosDaemon *daemon,
PinosPort *other_port, PinosPort *other_port,
const char *name, const char *name,

View file

@ -46,8 +46,10 @@ typedef struct {
void *user_data; void *user_data;
} InvokeItem; } InvokeItem;
struct _PinosDataLoopPrivate typedef struct
{ {
PinosDataLoop this;
SpaRingbuffer buffer; SpaRingbuffer buffer;
uint8_t buffer_data[DATAS_SIZE]; uint8_t buffer_data[DATAS_SIZE];
@ -64,20 +66,7 @@ struct _PinosDataLoopPrivate
bool running; bool running;
pthread_t thread; pthread_t thread;
} PinosDataLoopImpl;
};
G_DEFINE_TYPE (PinosDataLoop, pinos_data_loop, G_TYPE_OBJECT);
enum
{
PROP_0,
};
enum
{
LAST_SIGNAL
};
static void static void
make_realtime (PinosDataLoop *this) make_realtime (PinosDataLoop *this)
@ -126,23 +115,23 @@ make_realtime (PinosDataLoop *this)
static void * static void *
loop (void *user_data) loop (void *user_data)
{ {
PinosDataLoop *this = user_data; PinosDataLoopImpl *impl = user_data;
PinosDataLoopPrivate *priv = this->priv; PinosDataLoop *this = &impl->this;
SpaPoll *p = &this->poll; SpaPoll *p = &this->poll;
unsigned int i, j; unsigned int i, j;
make_realtime (this); make_realtime (this);
pinos_log_debug ("data-loop %p: enter thread", this); pinos_log_debug ("data-loop %p: enter thread", this);
while (priv->running) { while (impl->running) {
SpaPollNotifyData ndata; SpaPollNotifyData ndata;
unsigned int n_idle = 0; unsigned int n_idle = 0;
int r; int r;
struct timespec ts; struct timespec ts;
/* prepare */ /* prepare */
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
SpaPollItem *p = &priv->poll[i]; SpaPollItem *p = &impl->poll[i];
if (p->enabled && p->idle_cb) { if (p->enabled && p->idle_cb) {
ndata.fds = NULL; ndata.fds = NULL;
@ -157,28 +146,28 @@ loop (void *user_data)
// continue; // continue;
/* rebuild */ /* rebuild */
if (priv->rebuild_fds) { if (impl->rebuild_fds) {
priv->n_fds = 1; impl->n_fds = 1;
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
SpaPollItem *p = &priv->poll[i]; SpaPollItem *p = &impl->poll[i];
if (!p->enabled) if (!p->enabled)
continue; continue;
for (j = 0; j < p->n_fds; j++) for (j = 0; j < p->n_fds; j++)
priv->fds[priv->n_fds + j] = p->fds[j]; impl->fds[impl->n_fds + j] = p->fds[j];
priv->idx[i] = priv->n_fds; impl->idx[i] = impl->n_fds;
priv->n_fds += p->n_fds; impl->n_fds += p->n_fds;
} }
priv->rebuild_fds = false; impl->rebuild_fds = false;
} }
/* before */ /* before */
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
SpaPollItem *p = &priv->poll[i]; SpaPollItem *p = &impl->poll[i];
if (p->enabled && p->before_cb) { if (p->enabled && p->before_cb) {
ndata.fds = &priv->fds[priv->idx[i]]; ndata.fds = &impl->fds[impl->idx[i]];
ndata.n_fds = p->n_fds; ndata.n_fds = p->n_fds;
ndata.user_data = p->user_data; ndata.user_data = p->user_data;
if (SPA_RESULT_IS_ERROR (p->before_cb (&ndata))) if (SPA_RESULT_IS_ERROR (p->before_cb (&ndata)))
@ -186,7 +175,7 @@ loop (void *user_data)
} }
} }
r = poll ((struct pollfd *) priv->fds, priv->n_fds, -1); r = poll ((struct pollfd *) impl->fds, impl->n_fds, -1);
if (r < 0) { if (r < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
@ -198,17 +187,17 @@ loop (void *user_data)
} }
/* check wakeup */ /* check wakeup */
if (priv->fds[0].revents & POLLIN) { if (impl->fds[0].revents & POLLIN) {
uint64_t u; uint64_t u;
size_t offset; size_t offset;
if (read (priv->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) if (read (impl->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t))
pinos_log_warn ("data-loop %p: failed to read fd: %s", this, strerror (errno)); pinos_log_warn ("data-loop %p: failed to read fd: %s", this, strerror (errno));
while (spa_ringbuffer_get_read_offset (&priv->buffer, &offset) > 0) { while (spa_ringbuffer_get_read_offset (&impl->buffer, &offset) > 0) {
InvokeItem *item = SPA_MEMBER (priv->buffer_data, offset, InvokeItem); InvokeItem *item = SPA_MEMBER (impl->buffer_data, offset, InvokeItem);
item->func (p, true, item->seq, item->size, item->data, item->user_data); item->func (p, true, item->seq, item->size, item->data, item->user_data);
spa_ringbuffer_read_advance (&priv->buffer, item->item_size); spa_ringbuffer_read_advance (&impl->buffer, item->item_size);
} }
continue; continue;
} }
@ -217,11 +206,11 @@ loop (void *user_data)
// fprintf (stderr, "%llu\n", SPA_TIMESPEC_TO_TIME (&ts)); // fprintf (stderr, "%llu\n", SPA_TIMESPEC_TO_TIME (&ts));
/* after */ /* after */
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
SpaPollItem *p = &priv->poll[i]; SpaPollItem *p = &impl->poll[i];
if (p->enabled && p->after_cb && (p->n_fds == 0 || priv->fds[priv->idx[i]].revents != 0)) { if (p->enabled && p->after_cb && (p->n_fds == 0 || impl->fds[impl->idx[i]].revents != 0)) {
ndata.fds = &priv->fds[priv->idx[i]]; ndata.fds = &impl->fds[impl->idx[i]];
ndata.n_fds = p->n_fds; ndata.n_fds = p->n_fds;
ndata.user_data = p->user_data; ndata.user_data = p->user_data;
if (SPA_RESULT_IS_ERROR (p->after_cb (&ndata))) if (SPA_RESULT_IS_ERROR (p->after_cb (&ndata)))
@ -235,40 +224,36 @@ loop (void *user_data)
} }
static void static void
wakeup_thread (PinosDataLoop *this) wakeup_thread (PinosDataLoopImpl *impl)
{ {
PinosDataLoopPrivate *priv = this->priv;
uint64_t u = 1; uint64_t u = 1;
if (write (priv->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) if (write (impl->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t))
pinos_log_warn ("data-loop %p: failed to write fd: %s", this, strerror (errno)); pinos_log_warn ("data-loop %p: failed to write fd: %s", impl, strerror (errno));
} }
static void static void
start_thread (PinosDataLoop *this) start_thread (PinosDataLoopImpl *impl)
{ {
PinosDataLoopPrivate *priv = this->priv;
int err; int err;
if (!priv->running) { if (!impl->running) {
priv->running = true; impl->running = true;
if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) { if ((err = pthread_create (&impl->thread, NULL, loop, impl)) != 0) {
pinos_log_warn ("data-loop %p: can't create thread: %s", this, strerror (err)); pinos_log_warn ("data-loop %p: can't create thread: %s", impl, strerror (err));
priv->running = false; impl->running = false;
} }
} }
} }
static void static void
stop_thread (PinosDataLoop *this, bool in_thread) stop_thread (PinosDataLoopImpl *impl, bool in_thread)
{ {
PinosDataLoopPrivate *priv = this->priv; if (impl->running) {
impl->running = false;
if (priv->running) {
priv->running = false;
if (!in_thread) { if (!in_thread) {
wakeup_thread (this); wakeup_thread (impl);
pthread_join (priv->thread, NULL); pthread_join (impl->thread, NULL);
} }
} }
} }
@ -278,18 +263,18 @@ do_add_item (SpaPoll *poll,
SpaPollItem *item) SpaPollItem *item)
{ {
PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
PinosDataLoopPrivate *priv = this->priv; PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
bool in_thread = pthread_equal (priv->thread, pthread_self()); bool in_thread = pthread_equal (impl->thread, pthread_self());
item->id = ++priv->counter; item->id = ++impl->counter;
priv->poll[priv->n_poll] = *item; impl->poll[impl->n_poll] = *item;
priv->n_poll++; impl->n_poll++;
if (item->n_fds) if (item->n_fds)
priv->rebuild_fds = true; impl->rebuild_fds = true;
if (!in_thread) { if (!in_thread) {
wakeup_thread (this); wakeup_thread (impl);
start_thread (this); start_thread (impl);
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -300,19 +285,19 @@ do_update_item (SpaPoll *poll,
SpaPollItem *item) SpaPollItem *item)
{ {
PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
PinosDataLoopPrivate *priv = this->priv; PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
bool in_thread = pthread_equal (priv->thread, pthread_self()); bool in_thread = pthread_equal (impl->thread, pthread_self());
unsigned int i; unsigned int i;
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
if (priv->poll[i].id == item->id) if (impl->poll[i].id == item->id)
priv->poll[i] = *item; impl->poll[i] = *item;
} }
if (item->n_fds) if (item->n_fds)
priv->rebuild_fds = true; impl->rebuild_fds = true;
if (!in_thread) if (!in_thread)
wakeup_thread (this); wakeup_thread (impl);
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -322,22 +307,22 @@ do_remove_item (SpaPoll *poll,
SpaPollItem *item) SpaPollItem *item)
{ {
PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
PinosDataLoopPrivate *priv = this->priv; PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
bool in_thread = pthread_equal (priv->thread, pthread_self()); bool in_thread = pthread_equal (impl->thread, pthread_self());
unsigned int i; unsigned int i;
for (i = 0; i < priv->n_poll; i++) { for (i = 0; i < impl->n_poll; i++) {
if (priv->poll[i].id == item->id) { if (impl->poll[i].id == item->id) {
priv->n_poll--; impl->n_poll--;
for (; i < priv->n_poll; i++) for (; i < impl->n_poll; i++)
priv->poll[i] = priv->poll[i+1]; impl->poll[i] = impl->poll[i+1];
break; break;
} }
} }
if (item->n_fds) { if (item->n_fds) {
priv->rebuild_fds = true; impl->rebuild_fds = true;
if (!in_thread) if (!in_thread)
wakeup_thread (this); wakeup_thread (impl);
} }
return SPA_RESULT_OK; return SPA_RESULT_OK;
} }
@ -351,8 +336,8 @@ do_invoke (SpaPoll *poll,
void *user_data) void *user_data)
{ {
PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
PinosDataLoopPrivate *priv = this->priv; PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
bool in_thread = pthread_equal (priv->thread, pthread_self()); bool in_thread = pthread_equal (impl->thread, pthread_self());
SpaRingbufferArea areas[2]; SpaRingbufferArea areas[2];
InvokeItem *item; InvokeItem *item;
SpaResult res; SpaResult res;
@ -360,12 +345,12 @@ do_invoke (SpaPoll *poll,
if (in_thread) { if (in_thread) {
res = func (poll, false, seq, size, data, user_data); res = func (poll, false, seq, size, data, user_data);
} else { } else {
spa_ringbuffer_get_write_areas (&priv->buffer, areas); spa_ringbuffer_get_write_areas (&impl->buffer, areas);
if (areas[0].len < sizeof (InvokeItem)) { if (areas[0].len < sizeof (InvokeItem)) {
pinos_log_warn ("queue full"); pinos_log_warn ("queue full");
return SPA_RESULT_ERROR; return SPA_RESULT_ERROR;
} }
item = SPA_MEMBER (priv->buffer_data, areas[0].offset, InvokeItem); item = SPA_MEMBER (impl->buffer_data, areas[0].offset, InvokeItem);
item->seq = seq; item->seq = seq;
item->func = func; item->func = func;
item->user_data = user_data; item->user_data = user_data;
@ -377,14 +362,14 @@ do_invoke (SpaPoll *poll,
if (areas[0].len < sizeof (InvokeItem) + item->item_size) if (areas[0].len < sizeof (InvokeItem) + item->item_size)
item->item_size = areas[0].len; item->item_size = areas[0].len;
} else { } else {
item->data = SPA_MEMBER (priv->buffer_data, areas[1].offset, void); item->data = SPA_MEMBER (impl->buffer_data, areas[1].offset, void);
item->item_size = areas[0].len + 1 + size; item->item_size = areas[0].len + 1 + size;
} }
memcpy (item->data, data, size); memcpy (item->data, data, size);
spa_ringbuffer_write_advance (&priv->buffer, item->item_size); spa_ringbuffer_write_advance (&impl->buffer, item->item_size);
wakeup_thread (this); wakeup_thread (impl);
if (seq != SPA_ID_INVALID) if (seq != SPA_ID_INVALID)
res = SPA_RESULT_RETURN_ASYNC (seq); res = SPA_RESULT_RETURN_ASYNC (seq);
@ -394,72 +379,6 @@ do_invoke (SpaPoll *poll,
return res; return res;
} }
static void
pinos_data_loop_constructed (GObject * obj)
{
PinosDataLoop *this = PINOS_DATA_LOOP (obj);
PinosDataLoopPrivate *priv = this->priv;
pinos_log_debug ("data-loop %p: constructed", this);
G_OBJECT_CLASS (pinos_data_loop_parent_class)->constructed (obj);
priv->fds[0].fd = eventfd (0, 0);
priv->fds[0].events = POLLIN | POLLPRI | POLLERR;
priv->fds[0].revents = 0;
priv->n_fds = 1;
}
static void
pinos_data_loop_dispose (GObject * obj)
{
PinosDataLoop *this = PINOS_DATA_LOOP (obj);
pinos_log_debug ("data-loop %p: dispose", this);
stop_thread (this, FALSE);
G_OBJECT_CLASS (pinos_data_loop_parent_class)->dispose (obj);
}
static void
pinos_data_loop_finalize (GObject * obj)
{
PinosDataLoop *this = PINOS_DATA_LOOP (obj);
pinos_log_debug ("data-loop %p: finalize", this);
G_OBJECT_CLASS (pinos_data_loop_parent_class)->finalize (obj);
}
static void
pinos_data_loop_class_init (PinosDataLoopClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (PinosDataLoopPrivate));
gobject_class->constructed = pinos_data_loop_constructed;
gobject_class->dispose = pinos_data_loop_dispose;
gobject_class->finalize = pinos_data_loop_finalize;
}
static void
pinos_data_loop_init (PinosDataLoop * this)
{
PinosDataLoopPrivate *priv = this->priv = PINOS_DATA_LOOP_GET_PRIVATE (this);
pinos_log_debug ("data-loop %p: new", this);
this->poll.size = sizeof (SpaPoll);
this->poll.info = NULL;
this->poll.add_item = do_add_item;
this->poll.update_item = do_update_item;
this->poll.remove_item = do_remove_item;
this->poll.invoke = do_invoke;
spa_ringbuffer_init (&priv->buffer, DATAS_SIZE);
}
/** /**
* pinos_data_loop_new: * pinos_data_loop_new:
* *
@ -470,11 +389,45 @@ pinos_data_loop_init (PinosDataLoop * this)
PinosDataLoop * PinosDataLoop *
pinos_data_loop_new (void) pinos_data_loop_new (void)
{ {
return g_object_new (PINOS_TYPE_DATA_LOOP, NULL); PinosDataLoopImpl *impl;
PinosDataLoop *this;
impl = calloc (1, sizeof (PinosDataLoopImpl));
this = &impl->this;
pinos_log_debug ("data-loop %p: new", impl);
this->poll.size = sizeof (SpaPoll);
this->poll.info = NULL;
this->poll.add_item = do_add_item;
this->poll.update_item = do_update_item;
this->poll.remove_item = do_remove_item;
this->poll.invoke = do_invoke;
impl->fds[0].fd = eventfd (0, 0);
impl->fds[0].events = POLLIN | POLLPRI | POLLERR;
impl->fds[0].revents = 0;
impl->n_fds = 1;
spa_ringbuffer_init (&impl->buffer, DATAS_SIZE);
return this;
}
void
pinos_data_loop_destroy (PinosDataLoop * loop)
{
PinosDataLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosDataLoopImpl, this);
pinos_log_debug ("data-loop %p: destroy", impl);
stop_thread (impl, FALSE);
close (impl->fds[0].fd);
free (impl);
} }
bool bool
pinos_data_loop_in_thread (PinosDataLoop *loop) pinos_data_loop_in_thread (PinosDataLoop *loop)
{ {
return pthread_equal (loop->priv->thread, pthread_self()); PinosDataLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosDataLoopImpl, this);
return pthread_equal (impl->thread, pthread_self());
} }

View file

@ -25,47 +25,20 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#include <spa/include/spa/poll.h> #include <spa/include/spa/poll.h>
#include <spa/include/spa/node-command.h>
typedef struct _PinosDataLoop PinosDataLoop; typedef struct _PinosDataLoop PinosDataLoop;
typedef struct _PinosDataLoopClass PinosDataLoopClass;
typedef struct _PinosDataLoopPrivate PinosDataLoopPrivate;
#define PINOS_TYPE_DATA_LOOP (pinos_data_loop_get_type ())
#define PINOS_IS_DATA_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_DATA_LOOP))
#define PINOS_IS_DATA_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_DATA_LOOP))
#define PINOS_DATA_LOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_DATA_LOOP, PinosDataLoopClass))
#define PINOS_DATA_LOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_DATA_LOOP, PinosDataLoop))
#define PINOS_DATA_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_DATA_LOOP, PinosDataLoopClass))
#define PINOS_DATA_LOOP_CAST(obj) ((PinosDataLoop*)(obj))
#define PINOS_DATA_LOOP_CLASS_CAST(klass) ((PinosDataLoopClass*)(klass))
/** /**
* PinosDataLoop: * PinosDataLoop:
* *
* Pinos rt-loop class. * Pinos rt-loop object.
*/ */
struct _PinosDataLoop { struct _PinosDataLoop {
GObject object;
SpaPoll poll; SpaPoll poll;
PinosDataLoopPrivate *priv;
}; };
/**
* PinosDataLoopClass:
*
* Pinos rt-loop class.
*/
struct _PinosDataLoopClass {
GObjectClass parent_class;
};
/* normal GObject stuff */
GType pinos_data_loop_get_type (void);
PinosDataLoop * pinos_data_loop_new (void); PinosDataLoop * pinos_data_loop_new (void);
void pinos_data_loop_destroy (PinosDataLoop *loop);
bool pinos_data_loop_in_thread (PinosDataLoop *loop); bool pinos_data_loop_in_thread (PinosDataLoop *loop);

View file

@ -38,22 +38,13 @@
typedef struct typedef struct
{ {
PinosLink link; PinosLink this;
PinosObject object;
PinosInterface ifaces[1];
PinosCore *core;
PinosDaemon *daemon;
PinosLink1 *iface; PinosLink1 *iface;
gchar *object_path;
GPtrArray *format_filter; GPtrArray *format_filter;
PinosProperties *properties; PinosProperties *properties;
PinosLinkState state;
GError *error;
PinosListener input_port_destroy; PinosListener input_port_destroy;
PinosListener input_async_complete; PinosListener input_async_complete;
PinosListener output_port_destroy; PinosListener output_port_destroy;
@ -65,60 +56,27 @@ typedef struct
unsigned int n_buffers; unsigned int n_buffers;
} PinosLinkImpl; } PinosLinkImpl;
static void
link_register_object (PinosLink *this)
{
PinosLinkImpl *impl = (PinosLinkImpl *) this;
PinosObjectSkeleton *skel;
gchar *name;
name = g_strdup_printf (PINOS_DBUS_OBJECT_LINK);
skel = pinos_object_skeleton_new (name);
g_free (name);
pinos_object_skeleton_set_link1 (skel, impl->iface);
g_free (impl->object_path);
impl->object_path = pinos_daemon_export_uniquely (impl->daemon, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
pinos_log_debug ("link %p: register object %s", this, impl->object_path);
}
static void
link_unregister_object (PinosLink *this)
{
PinosLinkImpl *impl = (PinosLinkImpl *) this;
pinos_log_debug ("link %p: unregister object", this);
pinos_daemon_unexport (impl->daemon, impl->object_path);
}
static void static void
pinos_link_update_state (PinosLink *link, PinosLinkState state) pinos_link_update_state (PinosLink *link, PinosLinkState state)
{ {
PinosLinkImpl *impl = (PinosLinkImpl *) link; if (state != link->state) {
g_clear_error (&link->error);
if (state != impl->state) {
g_clear_error (&impl->error);
pinos_log_debug ("link %p: update state %s -> %s", link, pinos_log_debug ("link %p: update state %s -> %s", link,
pinos_link_state_as_string (impl->state), pinos_link_state_as_string (link->state),
pinos_link_state_as_string (state)); pinos_link_state_as_string (state));
impl->state = state; link->state = state;
pinos_signal_emit (&link->notify_state, link, NULL); pinos_signal_emit (&link->core->link_state_changed, link);
} }
} }
static void static void
pinos_link_report_error (PinosLink *link, GError *error) pinos_link_report_error (PinosLink *link, GError *error)
{ {
PinosLinkImpl *impl = (PinosLinkImpl *) link; g_clear_error (&link->error);
link->error = error;
g_clear_error (&impl->error); link->state = PINOS_LINK_STATE_ERROR;
impl->error = error;
impl->state = PINOS_LINK_STATE_ERROR;
pinos_log_debug ("link %p: got error state %s", link, error->message); pinos_log_debug ("link %p: got error state %s", link, error->message);
pinos_signal_emit (&link->notify_state, link, NULL); pinos_signal_emit (&link->core->link_state_changed, link);
} }
static SpaResult static SpaResult
@ -152,7 +110,7 @@ again:
goto error; goto error;
} }
} }
pinos_log_debug ("Try filter:"); pinos_log_debug ("Try filter: %p", filter);
spa_debug_format (filter); spa_debug_format (filter);
if ((res = spa_node_port_enum_formats (this->output->node->node, if ((res = spa_node_port_enum_formats (this->output->node->node,
@ -269,7 +227,7 @@ find_meta_enable (const SpaPortInfo *info, SpaMetaType type)
static SpaResult static SpaResult
do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
{ {
PinosLinkImpl *impl = (PinosLinkImpl *) this; PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this);
SpaResult res; SpaResult res;
const SpaPortInfo *iinfo, *oinfo; const SpaPortInfo *iinfo, *oinfo;
SpaPortInfoFlags in_flags, out_flags; SpaPortInfoFlags in_flags, out_flags;
@ -608,7 +566,6 @@ check_states (PinosLink *this,
SpaResult res) SpaResult res)
{ {
SpaNodeState in_state, out_state; SpaNodeState in_state, out_state;
PinosLinkImpl *impl = (PinosLinkImpl *) this;
if (res != SPA_RESULT_OK) { if (res != SPA_RESULT_OK) {
pinos_log_warn ("link %p: error: %d", this, res); pinos_log_warn ("link %p: error: %d", this, res);
@ -641,34 +598,34 @@ again:
return SPA_RESULT_OK; return SPA_RESULT_OK;
exit: exit:
pinos_main_loop_defer (impl->core->main_loop, this, res, (PinosDeferFunc) check_states, this, NULL); pinos_main_loop_defer (this->core->main_loop, this, res, (PinosDeferFunc) check_states, this, NULL);
return res; return res;
} }
static void static void
on_input_async_complete_notify (PinosListener *listener, on_input_async_complete_notify (PinosListener *listener,
void *object, PinosNode *node,
void *data) uint32_t seq,
SpaResult res)
{ {
PinosNode *node = object;
PinosNodeAsyncCompleteData *d = data;
PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, input_async_complete); PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, input_async_complete);
PinosLink *this = &impl->this;
pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, d->seq, d->res); pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, seq, res);
pinos_main_loop_defer_complete (impl->core->main_loop, impl, d->seq, d->res); pinos_main_loop_defer_complete (this->core->main_loop, impl, seq, res);
} }
static void static void
on_output_async_complete_notify (PinosListener *listener, on_output_async_complete_notify (PinosListener *listener,
void *object, PinosNode *node,
void *data) uint32_t seq,
SpaResult res)
{ {
PinosNode *node = object;
PinosNodeAsyncCompleteData *d = data;
PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, output_async_complete); PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, output_async_complete);
PinosLink *this = &impl->this;
pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, d->seq, d->res); pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, seq, res);
pinos_main_loop_defer_complete (impl->core->main_loop, impl, d->seq, d->res); pinos_main_loop_defer_complete (this->core->main_loop, impl, seq, res);
} }
#if 0 #if 0
@ -704,7 +661,7 @@ on_property_notify (GObject *obj,
static void static void
on_port_unlinked (PinosPort *port, PinosLink *this, SpaResult res, gulong id) on_port_unlinked (PinosPort *port, PinosLink *this, SpaResult res, gulong id)
{ {
pinos_signal_emit (&this->port_unlinked, this, port); pinos_signal_emit (&this->core->port_unlinked, this, port);
if (this->input == NULL || this->output == NULL) if (this->input == NULL || this->output == NULL)
pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED); pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED);
@ -734,7 +691,7 @@ on_port_destroy (PinosLink *this,
} }
res = pinos_port_unlink (port, this); res = pinos_port_unlink (port, this);
pinos_main_loop_defer (impl->core->main_loop, pinos_main_loop_defer (this->core->main_loop,
port, port,
res, res,
(PinosDeferFunc) on_port_unlinked, (PinosDeferFunc) on_port_unlinked,
@ -744,73 +701,34 @@ on_port_destroy (PinosLink *this,
static void static void
on_input_port_destroy (PinosListener *listener, on_input_port_destroy (PinosListener *listener,
void *object, PinosPort *port)
void *data)
{ {
PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, input_port_destroy); PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, input_port_destroy);
PinosPort *port = object;
on_port_destroy (&impl->link, port); on_port_destroy (&impl->this, port);
pinos_signal_remove (listener); pinos_signal_remove (listener);
} }
static void static void
on_output_port_destroy (PinosListener *listener, on_output_port_destroy (PinosListener *listener,
void *object, PinosPort *port)
void *data)
{ {
PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, output_port_destroy); PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, output_port_destroy);
PinosPort *port = object;
on_port_destroy (&impl->link, port); on_port_destroy (&impl->this, port);
pinos_signal_remove (listener); pinos_signal_remove (listener);
} }
static void bool
link_destroy (PinosObject * object) pinos_link_activate (PinosLink *this)
{
PinosLinkImpl *impl = (PinosLinkImpl *) object;
PinosLink *this = &impl->link;
pinos_log_debug ("link %p: destroy", this);
if (this->input)
pinos_signal_remove (&impl->input_port_destroy);
if (this->output)
pinos_signal_remove (&impl->output_port_destroy);
if (this->input)
pinos_port_unlink (this->input, this);
if (this->output)
pinos_port_unlink (this->output, this);
link_unregister_object (this);
pinos_main_loop_defer_cancel (impl->core->main_loop, this, 0);
g_clear_object (&impl->daemon);
g_clear_object (&impl->iface);
g_free (impl->object_path);
if (impl->allocated)
pinos_memblock_free (&impl->buffer_mem);
pinos_registry_remove_object (&impl->core->registry, &this->object);
free (object);
}
static bool
link_activate (PinosLink *this)
{ {
spa_ringbuffer_init (&this->ringbuffer, SPA_N_ELEMENTS (this->queue)); spa_ringbuffer_init (&this->ringbuffer, SPA_N_ELEMENTS (this->queue));
check_states (this, NULL, SPA_RESULT_OK); check_states (this, NULL, SPA_RESULT_OK);
return true; return true;
} }
static bool bool
pinos_link_deactivate (PinosLink *this) pinos_pinos_link_deactivate (PinosLink *this)
{ {
spa_ringbuffer_clear (&this->ringbuffer); spa_ringbuffer_clear (&this->ringbuffer);
return true; return true;
@ -818,60 +736,61 @@ pinos_link_deactivate (PinosLink *this)
PinosLink * PinosLink *
pinos_link_new (PinosCore *core, pinos_link_new (PinosCore *core,
PinosPort *input,
PinosPort *output, PinosPort *output,
PinosPort *input,
GPtrArray *format_filter, GPtrArray *format_filter,
PinosProperties *properties) PinosProperties *properties)
{ {
PinosLinkImpl *impl; PinosLinkImpl *impl;
PinosLink *this; PinosLink *this;
PinosObjectSkeleton *skel;
impl = calloc (1, sizeof (PinosLinkImpl)); impl = calloc (1, sizeof (PinosLinkImpl));
this = &impl->link; this = &impl->this;
pinos_log_debug ("link %p: new", this); pinos_log_debug ("link %p: new", this);
this->core = core;
this->properties = properties; this->properties = properties;
this->state = PINOS_LINK_STATE_INIT; this->state = PINOS_LINK_STATE_INIT;
this->input = input; this->input = input;
this->output = output; this->output = output;
pinos_signal_init (&this->notify_state); pinos_signal_init (&this->destroy_signal);
pinos_signal_init (&this->port_unlinked);
this->activate = link_activate;
this->deactivate = link_deactivate;
impl->format_filter = format_filter; impl->format_filter = format_filter;
impl->iface = pinos_link1_skeleton_new ();
impl->input_port_destroy.notify = on_input_port_destroy; pinos_signal_add (&this->input->destroy_signal,
pinos_signal_add (&this->input->object.destroy_signal, &impl->input_port_destroy); &impl->input_port_destroy,
on_input_port_destroy);
impl->output_port_destroy.notify = on_output_port_destroy; pinos_signal_add (&this->output->destroy_signal,
pinos_signal_add (&this->output->object.destroy_signal, &impl->output_port_destroy); &impl->output_port_destroy,
on_output_port_destroy);
impl->input_async_complete.notify = on_input_async_complete_notify; pinos_signal_add (&this->input->node->async_complete,
pinos_signal_add (&this->input->node->async_complete, &impl->input_async_complete); &impl->input_async_complete,
on_input_async_complete_notify);
impl->output_async_complete.notify = on_output_async_complete_notify; pinos_signal_add (&this->output->node->async_complete,
pinos_signal_add (&this->output->node->async_complete, &impl->output_async_complete); &impl->output_async_complete,
on_output_async_complete_notify);
impl->ifaces[0].type = core->registry.uri.link;
impl->ifaces[0].iface = this;
pinos_object_init (&this->object,
link_destroy,
1,
impl->ifaces);
pinos_registry_add_object (&core->registry, &this->object);
pinos_log_debug ("link %p: constructed %p:%d -> %p:%d", impl, pinos_log_debug ("link %p: constructed %p:%d -> %p:%d", impl,
this->output->node, this->output->port, this->output->node, this->output->port,
this->input->node, this->input->port); this->input->node, this->input->port);
link_register_object (this);
return &this->object; spa_list_insert (core->link_list.prev, &this->list);
impl->iface = pinos_link1_skeleton_new ();
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_LINK);
pinos_object_skeleton_set_link1 (skel, impl->iface);
this->global = pinos_core_add_global (core,
core->registry.uri.link,
this,
skel);
return this;
} }
/** /**
@ -881,40 +800,34 @@ pinos_link_new (PinosCore *core,
* Trigger removal of @link * Trigger removal of @link
*/ */
void void
pinos_link_destroy (PinosLink *this) pinos_link_destroy (PinosLink * this)
{ {
pinos_log_debug ("link %p: destroy", this); PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this);
pinos_signal_emit (&this->object.destroy_signal, this, NULL);
} pinos_log_debug ("link %p: destroy", impl);
pinos_signal_emit (&this->destroy_signal, this);
/**
* pinos_link_get_object_path: if (this->input) {
* @link: a #PinosLink pinos_signal_remove (&impl->input_port_destroy);
* pinos_signal_remove (&impl->input_async_complete);
* Get the object patch of @link pinos_port_unlink (this->input, this);
* }
* Returns: the object path of @source. if (this->output) {
*/ pinos_signal_remove (&impl->output_port_destroy);
const gchar * pinos_signal_remove (&impl->output_async_complete);
pinos_link_get_object_path (PinosLink *this) pinos_port_unlink (this->output, this);
{ }
PinosLinkImpl *impl = (PinosLinkImpl *) this;
pinos_main_loop_defer_cancel (this->core->main_loop, this, 0);
g_return_val_if_fail (impl, NULL);
pinos_core_remove_global (this->core, this->global);
return impl->object_path;
} spa_list_remove (&this->list);
PinosLinkState g_clear_object (&impl->iface);
pinos_link_get_state (PinosLink *this,
GError **error) if (impl->allocated)
{ pinos_memblock_free (&impl->buffer_mem);
PinosLinkImpl *impl = (PinosLinkImpl *) this;
free (impl);
g_return_val_if_fail (impl, PINOS_LINK_STATE_ERROR);
if (error)
*error = impl->error;
return impl->state;
} }

View file

@ -24,11 +24,11 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _PinosLink PinosLink;
#define PINOS_LINK_URI "http://pinos.org/ns/link" #define PINOS_LINK_URI "http://pinos.org/ns/link"
#define PINOS_LINK_PREFIX PINOS_LINK_URI "#" #define PINOS_LINK_PREFIX PINOS_LINK_URI "#"
typedef struct _PinosLink PinosLink;
#include <spa/include/spa/ringbuffer.h> #include <spa/include/spa/ringbuffer.h>
#include <pinos/client/mem.h> #include <pinos/client/mem.h>
@ -43,33 +43,38 @@ typedef struct _PinosLink PinosLink;
* Pinos link interface. * Pinos link interface.
*/ */
struct _PinosLink { struct _PinosLink {
PinosCore *core;
SpaList list;
PinosGlobal *global;
PinosProperties *properties; PinosProperties *properties;
PinosLinkState state; PinosLinkState state;
GError *error; GError *error;
PINOS_SIGNAL (destroy_signal, (PinosListener *,
PinosLink *));
PinosPort *output; PinosPort *output;
PinosPort *input; PinosPort *input;
PinosSignal port_unlinked;
PinosSignal notify_state;
uint32_t queue[64]; uint32_t queue[64];
SpaRingbuffer ringbuffer; SpaRingbuffer ringbuffer;
gint in_ready; gint in_ready;
bool (*activate) (PinosLink *link);
bool (*deactivate) (PinosLink *link);
}; };
PinosObject * pinos_link_new (PinosCore *core,
PinosPort *input, PinosLink * pinos_link_new (PinosCore *core,
PinosPort *output, PinosPort *output,
PinosPort *input,
GPtrArray *format_filter, GPtrArray *format_filter,
PinosProperties *properties); PinosProperties *properties);
void pinos_link_destroy (PinosLink *link);
bool pinos_link_activate (PinosLink *link);
bool pinos_link_deactivate (PinosLink *link);
#define pinos_link_activate(l) (l)->activate(l)
#define pinos_link_deactivate(l) (l)->deactivate(l)
const gchar * pinos_link_get_object_path (PinosLink *link); const gchar * pinos_link_get_object_path (PinosLink *link);

View file

@ -62,8 +62,6 @@ typedef struct
{ {
PinosMainLoop this; PinosMainLoop this;
PinosObject object;
SpaPoll poll; SpaPoll poll;
GMainContext *context; GMainContext *context;
@ -343,6 +341,7 @@ static void
main_loop_quit (PinosMainLoop *loop) main_loop_quit (PinosMainLoop *loop)
{ {
PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this); PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
pinos_log_debug ("main-loop %p: quit", impl);
g_main_loop_quit (impl->loop); g_main_loop_quit (impl->loop);
} }
@ -350,20 +349,10 @@ static void
main_loop_run (PinosMainLoop *loop) main_loop_run (PinosMainLoop *loop)
{ {
PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this); PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
pinos_log_debug ("main-loop %p: run", impl);
g_main_loop_run (impl->loop); g_main_loop_run (impl->loop);
} }
void
pinos_main_loop_destroy (PinosMainLoop *loop)
{
PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
pinos_log_debug ("main-loop %p: destroy", impl);
g_slice_free_chain (WorkItem, impl->free_list, list.next);
free (impl);
}
/** /**
* pinos_main_loop_new: * pinos_main_loop_new:
* @context: a #GMainContext or %NULL to use the default context * @context: a #GMainContext or %NULL to use the default context
@ -418,3 +407,18 @@ pinos_main_loop_new (GMainContext *context)
return this; return this;
} }
void
pinos_main_loop_destroy (PinosMainLoop *loop)
{
PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
pinos_log_debug ("main-loop %p: destroy", impl);
g_main_loop_unref (impl->loop);
close (impl->fds[0].fd);
g_slice_free_chain (WorkItem, impl->free_list, list.next);
free (impl);
}

View file

@ -22,10 +22,10 @@
#include "config.h" #include "config.h"
#endif #endif
#include <glib.h> #include <dlfcn.h>
#include <gmodule.h>
#include "pinos/client/pinos.h" #include "pinos/client/pinos.h"
#include "pinos/client/utils.h"
#include "pinos/server/module.h" #include "pinos/server/module.h"
#define PINOS_SYMBOL_MODULE_INIT "pinos__module_init" #define PINOS_SYMBOL_MODULE_INIT "pinos__module_init"
@ -34,38 +34,11 @@ typedef struct
{ {
PinosModule this; PinosModule this;
PinosObject object; void *hnd;
PinosInterface ifaces[1];
GModule *module;
} PinosModuleImpl; } PinosModuleImpl;
static char *
static void find_module (const char * path, const char *name)
module_destroy (PinosObject * object)
{
PinosModuleImpl *impl = SPA_CONTAINER_OF (object, PinosModuleImpl, object);
PinosModule *this = &impl->this;
free (this->name);
g_module_close (impl->module);
free (impl);
}
GQuark
pinos_module_error_quark (void)
{
static GQuark quark = 0;
if (quark == 0) {
quark = g_quark_from_static_string ("pinos_module_error");
}
return quark;
}
static gchar *
find_module (const gchar * path, const gchar *name)
{ {
gchar *filename; gchar *filename;
GDir *dir; GDir *dir;
@ -113,7 +86,7 @@ find_module (const gchar * path, const gchar *name)
* @core: a #PinosCore * @core: a #PinosCore
* @name: name of the module to load * @name: name of the module to load
* @args: A string with arguments for the module * @args: A string with arguments for the module
* @err: Return location for a #GError, or %NULL * @err: Return location for an error string, or %NULL
* *
* Load module with @name. * Load module with @name.
* *
@ -123,96 +96,95 @@ PinosModule *
pinos_module_load (PinosCore *core, pinos_module_load (PinosCore *core,
const gchar *name, const gchar *name,
const gchar *args, const gchar *args,
GError **err) char **err)
{ {
PinosModule *this; PinosModule *this;
PinosModuleImpl *impl; PinosModuleImpl *impl;
GModule *gmodule; void *hnd;
gchar *filename = NULL; char *filename = NULL;
const gchar *module_dir; const char *module_dir;
PinosModuleInitFunc init_func; PinosModuleInitFunc init_func;
g_return_val_if_fail (name != NULL && name[0] != '\0', NULL); module_dir = getenv ("PINOS_MODULE_DIR");
g_return_val_if_fail (core, NULL);
if (!g_module_supported ()) {
g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_LOADING,
"Dynamic module loading not supported");
return NULL;
}
module_dir = g_getenv ("PINOS_MODULE_DIR");
if (module_dir != NULL) { if (module_dir != NULL) {
gchar **l; char **l;
gint i; int i, n_paths;
pinos_log_debug ("PINOS_MODULE_DIR set to: %s", module_dir); pinos_log_debug ("PINOS_MODULE_DIR set to: %s", module_dir);
l = g_strsplit (module_dir, G_SEARCHPATH_SEPARATOR_S, 0); l = pinos_split_strv (module_dir, G_SEARCHPATH_SEPARATOR_S, 0, &n_paths);
for (i = 0; l[i] != NULL; i++) { for (i = 0; l[i] != NULL; i++) {
filename = find_module (l[i], name); filename = find_module (l[i], name);
if (filename != NULL) if (filename != NULL)
break; break;
} }
g_strfreev (l); pinos_free_strv (l);
} else { } else {
pinos_log_debug ("moduledir set to: %s", MODULEDIR); pinos_log_debug ("moduledir set to: %s", MODULEDIR);
filename = find_module (MODULEDIR, name); filename = find_module (MODULEDIR, name);
} }
if (filename == NULL) { if (filename == NULL)
g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_NOT_FOUND, goto not_found;
"No module \"%s\" was found", name);
return NULL;
}
pinos_log_debug ("trying to load module: %s (%s)", name, filename); pinos_log_debug ("trying to load module: %s (%s)", name, filename);
gmodule = g_module_open (filename, G_MODULE_BIND_LOCAL); hnd = dlopen (filename, RTLD_NOW | RTLD_LOCAL);
g_free (filename); free (filename);
if (gmodule == NULL) { if (hnd == NULL)
g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_LOADING, goto open_failed;
"Failed to open module: %s", g_module_error ());
return NULL;
}
if (!g_module_symbol (gmodule, PINOS_SYMBOL_MODULE_INIT, if ((init_func = dlsym (hnd, PINOS_SYMBOL_MODULE_INIT)) == NULL)
(gpointer *) &init_func)) { goto no_pinos_module;
g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_LOADING,
"\"%s\" is not a pinos module", name);
g_module_close (gmodule);
return NULL;
}
impl = calloc (1, sizeof (PinosModuleImpl)); impl = calloc (1, sizeof (PinosModuleImpl));
impl->module = gmodule; impl->hnd = hnd;
this = &impl->this; this = &impl->this;
this->name = strdup (name); this->name = strdup (name);
this->core = core; this->core = core;
impl->ifaces[0].type = impl->core->registry.uri.module; if (!init_func (this, (gchar *) args))
impl->ifaces[0].iface = this; goto init_failed;
pinos_object_init (&impl->object,
module_destroy,
1,
impl->ifaces);
/* don't unload this module again */
g_module_make_resident (gmodule);
if (!init_func (this, (gchar *) args)) {
g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_INIT,
"\"%s\" failed to initialize", name);
module_destroy (this);
return NULL;
}
pinos_log_debug ("loaded module: %s", this->name); pinos_log_debug ("loaded module: %s", this->name);
return &this->object; return this;
not_found:
{
asprintf (err, "No module \"%s\" was found", name);
return NULL;
}
open_failed:
{
asprintf (err, "Failed to open module: %s", dlerror ());
return NULL;
}
no_pinos_module:
{
asprintf (err, "\"%s\" is not a pinos module", name);
dlclose (hnd);
return NULL;
}
init_failed:
{
asprintf (err, "\"%s\" failed to initialize", name);
pinos_module_destroy (this);
return NULL;
}
}
void
pinos_module_destroy (PinosModule *this)
{
PinosModuleImpl *impl = SPA_CONTAINER_OF (this, PinosModuleImpl, this);
pinos_signal_emit (&this->destroy_signal, this);
free (this->name);
dlclose (impl->hnd);
free (impl);
} }

View file

@ -21,47 +21,20 @@
#ifndef __PINOS_MODULE_H__ #ifndef __PINOS_MODULE_H__
#define __PINOS_MODULE_H__ #define __PINOS_MODULE_H__
#include <glib-object.h>
G_BEGIN_DECLS
#include <pinos/server/core.h> #include <pinos/server/core.h>
#define PINOS_MODULE_URI "http://pinos.org/ns/module"
#define PINOS_MODULE_PREFIX PINOS_MODULE_URI "#"
typedef struct _PinosModule PinosModule; typedef struct _PinosModule PinosModule;
struct _PinosModule { struct _PinosModule {
SpaList link;
gchar *name; gchar *name;
PinosCore *core; PinosCore *core;
PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosModule *module));
}; };
GQuark pinos_module_error_quark (void);
/**
* PINOS_MODULE_ERROR:
*
* Pinos module error.
*/
#define PINOS_MODULE_ERROR pinos_module_error_quark ()
/**
* PinosModuleError:
* @PINOS_MODULE_ERROR_GENERIC: Generic module error.
* @PINOS_MODULE_ERROR_NOT_FOUND: Module could not be found.
* @PINOS_MODULE_ERROR_LOADING: Module could not be loaded.
* @PINOS_MODULE_ERROR_INIT: The module failed to initialize.
*
* Error codes for Pinos modules.
*/
typedef enum
{
PINOS_MODULE_ERROR_GENERIC,
PINOS_MODULE_ERROR_NOT_FOUND,
PINOS_MODULE_ERROR_LOADING,
PINOS_MODULE_ERROR_INIT,
} PinosModuleError;
/** /**
* PinosModuleInitFunc: * PinosModuleInitFunc:
* @module: A #PinosModule * @module: A #PinosModule
@ -70,14 +43,15 @@ typedef enum
* A module should provide an init function with this signature. This function * A module should provide an init function with this signature. This function
* will be called when a module is loaded. * will be called when a module is loaded.
* *
* Returns: %TRUE on success, %FALSE otherwise * Returns: %true on success, %false otherwise
*/ */
typedef gboolean (*PinosModuleInitFunc) (PinosModule *module, gchar *args); typedef bool (*PinosModuleInitFunc) (PinosModule *module, char *args);
PinosObject * pinos_module_load (PinosCore *core, PinosModule * pinos_module_load (PinosCore *core,
const gchar *name, const gchar *name,
const gchar *args, const gchar *args,
GError **err); char **err);
void pinos_module_destroy (PinosModule *module);
G_END_DECLS G_END_DECLS

View file

@ -40,6 +40,7 @@ new_pinos_port (PinosNode *node, PinosDirection direction, uint32_t port)
np->direction = direction; np->direction = direction;
np->port = port; np->port = port;
np->links = g_ptr_array_new (); np->links = g_ptr_array_new ();
pinos_signal_init (&np->destroy_signal);
return np; return np;
} }
@ -52,16 +53,10 @@ free_node_port (PinosPort *np)
typedef struct typedef struct
{ {
PinosNode node; PinosNode this;
PinosObject object;
PinosInterface ifaces[1];
PinosCore *core;
PinosDaemon *daemon;
PinosNode1 *iface;
PinosClient *client; PinosClient *client;
gchar *object_path; PinosNode1 *iface;
uint32_t seq; uint32_t seq;
@ -74,8 +69,6 @@ typedef struct
GError *error; GError *error;
guint idle_timeout; guint idle_timeout;
PinosDataLoop *data_loop;
struct { struct {
GPtrArray *links; GPtrArray *links;
} rt; } rt;
@ -87,7 +80,7 @@ static void init_complete (PinosNode *this);
static void static void
update_port_ids (PinosNode *node, gboolean create) update_port_ids (PinosNode *node, gboolean create)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
uint32_t *input_port_ids, *output_port_ids; uint32_t *input_port_ids, *output_port_ids;
guint n_input_ports, n_output_ports, max_input_ports, max_output_ports; guint n_input_ports, n_output_ports, max_input_ports, max_output_ports;
guint i; guint i;
@ -130,7 +123,7 @@ update_port_ids (PinosNode *node, gboolean create)
impl->input_ports = g_list_insert_before (impl->input_ports, ports, np); impl->input_ports = g_list_insert_before (impl->input_ports, ports, np);
if (!impl->async_init) if (!impl->async_init)
pinos_signal_emit (&node->port_added, node, np); pinos_signal_emit (&node->core->port_added, node, np);
i++; i++;
} else if (p) { } else if (p) {
GList *next; GList *next;
@ -141,7 +134,7 @@ update_port_ids (PinosNode *node, gboolean create)
ports = next; ports = next;
if (!impl->async_init) if (!impl->async_init)
pinos_signal_emit (&node->port_removed, node, p); pinos_signal_emit (&node->core->port_removed, node, p);
free_node_port (p); free_node_port (p);
} else } else
@ -164,7 +157,7 @@ update_port_ids (PinosNode *node, gboolean create)
impl->output_ports = g_list_insert_before (impl->output_ports, ports, np); impl->output_ports = g_list_insert_before (impl->output_ports, ports, np);
if (!impl->async_init) if (!impl->async_init)
pinos_signal_emit (&node->port_added, node, np); pinos_signal_emit (&node->core->port_added, node, np);
i++; i++;
} else if (p) { } else if (p) {
GList *next; GList *next;
@ -175,7 +168,7 @@ update_port_ids (PinosNode *node, gboolean create)
ports = next; ports = next;
if (!impl->async_init) if (!impl->async_init)
pinos_signal_emit (&node->port_removed, node, p); pinos_signal_emit (&node->core->port_removed, node, p);
free_node_port (p); free_node_port (p);
} else } else
@ -196,7 +189,7 @@ update_port_ids (PinosNode *node, gboolean create)
for (i = 0; i < max_output_ports; i++) for (i = 0; i < max_output_ports; i++)
spa_node_port_set_output (node->node, i, &node->transport->outputs[i]); spa_node_port_set_output (node->node, i, &node->transport->outputs[i]);
pinos_signal_emit (&node->transport_changed, node, node->transport); pinos_signal_emit (&node->transport_changed, node);
} }
static SpaResult static SpaResult
@ -234,7 +227,7 @@ start_node (PinosNode *this)
static SpaResult static SpaResult
suspend_node (PinosNode *this) suspend_node (PinosNode *this)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
SpaResult res = SPA_RESULT_OK; SpaResult res = SPA_RESULT_OK;
GList *walk; GList *walk;
@ -326,7 +319,7 @@ static void
on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
{ {
PinosNode *this = user_data; PinosNode *this = user_data;
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
switch (event->type) { switch (event->type) {
case SPA_NODE_EVENT_TYPE_INVALID: case SPA_NODE_EVENT_TYPE_INVALID:
@ -340,9 +333,8 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
SpaNodeEventAsyncComplete *ac = (SpaNodeEventAsyncComplete *) event; SpaNodeEventAsyncComplete *ac = (SpaNodeEventAsyncComplete *) event;
pinos_log_debug ("node %p: async complete event %d %d", this, ac->seq, ac->res); pinos_log_debug ("node %p: async complete event %d %d", this, ac->seq, ac->res);
if (!pinos_main_loop_defer_complete (impl->core->main_loop, this, ac->seq, ac->res)) { if (!pinos_main_loop_defer_complete (this->core->main_loop, this, ac->seq, ac->res)) {
PinosNodeAsyncCompleteData acd = { ac->seq, ac->res }; pinos_signal_emit (&this->async_complete, this, ac->seq, ac->res);
pinos_signal_emit (&this->async_complete, this, &acd);
} }
break; break;
} }
@ -359,7 +351,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
continue; continue;
link->in_ready++; link->in_ready++;
spa_poll_invoke (&((PinosNodeImpl*)link->input->node)->data_loop->poll, spa_poll_invoke (&link->input->node->data_loop->poll,
do_read_link, do_read_link,
SPA_ID_INVALID, SPA_ID_INVALID,
sizeof (PinosLink *), sizeof (PinosLink *),
@ -395,7 +387,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
link->queue[offset] = po->buffer_id; link->queue[offset] = po->buffer_id;
spa_ringbuffer_write_advance (&link->ringbuffer, 1); spa_ringbuffer_write_advance (&link->ringbuffer, 1);
spa_poll_invoke (&((PinosNodeImpl*)link->input->node)->data_loop->poll, spa_poll_invoke (&link->input->node->data_loop->poll,
do_read_link, do_read_link,
SPA_ID_INVALID, SPA_ID_INVALID,
sizeof (PinosLink *), sizeof (PinosLink *),
@ -441,105 +433,41 @@ handle_remove (PinosNode1 *interface,
gpointer user_data) gpointer user_data)
{ {
PinosNode *this = user_data; PinosNode *this = user_data;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
pinos_log_debug ("node %p: remove", this); pinos_log_debug ("node %p: remove", this);
pinos_object_destroy (&this->object); pinos_node_destroy (this);
g_dbus_method_invocation_return_value (invocation, g_dbus_method_invocation_return_value (invocation,
g_variant_new ("()")); g_variant_new ("()"));
return TRUE; return TRUE;
} }
static void
node_register_object (PinosNode *this)
{
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
PinosDaemon *daemon = impl->daemon;
PinosObjectSkeleton *skel;
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_NODE);
pinos_object_skeleton_set_node1 (skel, impl->iface);
g_free (impl->object_path);
impl->object_path = pinos_daemon_export_uniquely (daemon, G_DBUS_OBJECT_SKELETON (skel));
g_object_unref (skel);
pinos_log_debug ("node %p: register object %s, id %u", this, impl->object_path, impl->object.id);
return;
}
static void
node_unregister_object (PinosNode *this)
{
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
pinos_log_debug ("node %p: unregister object %s", this, impl->object_path);
pinos_daemon_unexport (impl->daemon, impl->object_path);
g_clear_pointer (&impl->object_path, g_free);
}
static void
on_property_notify (GObject *obj,
GParamSpec *pspec,
gpointer user_data)
{
PinosNode *this = user_data;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "client") == 0) {
if (impl->client)
pinos_node1_set_owner (impl->iface, pinos_client_get_object_path (impl->client));
else
pinos_node1_set_owner (impl->iface, pinos_daemon_get_object_path (impl->daemon));
}
if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "name") == 0) {
pinos_node1_set_name (impl->iface, this->name);
}
if (pspec == NULL || strcmp (g_param_spec_get_name (pspec), "properties") == 0) {
PinosProperties *props = this->properties;
pinos_node1_set_properties (impl->iface, props ? pinos_properties_to_variant (props) : NULL);
}
}
static void static void
init_complete (PinosNode *this) init_complete (PinosNode *this)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
PinosProperties *props = this->properties;
update_port_ids (this, FALSE); update_port_ids (this, false);
pinos_log_debug ("node %p: init completed", this); pinos_log_debug ("node %p: init completed", this);
impl->async_init = FALSE; impl->async_init = false;
on_property_notify (G_OBJECT (this), NULL, this);
if (impl->client)
pinos_node1_set_owner (impl->iface, this->global->object_path);
else
pinos_node1_set_owner (impl->iface, "/");
pinos_node1_set_name (impl->iface, this->name);
pinos_node1_set_properties (impl->iface, props ? pinos_properties_to_variant (props) : NULL);
pinos_node_update_state (this, PINOS_NODE_STATE_SUSPENDED); pinos_node_update_state (this, PINOS_NODE_STATE_SUSPENDED);
} }
static void void
node_destroy (PinosObject * obj) pinos_node_set_data_loop (PinosNode *node,
PinosDataLoop *loop)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (obj, PinosNodeImpl, object); node->data_loop = loop;
PinosNode *this = &impl->node; pinos_signal_emit (&node->loop_changed, node);
pinos_log_debug ("node %p: destroy", this);
pinos_node_set_state (this, PINOS_NODE_STATE_SUSPENDED);
node_unregister_object (this);
pinos_main_loop_defer_cancel (impl->core->main_loop, this, 0);
pinos_registry_remove_object (&impl->core->registry, &impl->object);
g_clear_object (&impl->daemon);
g_clear_object (&impl->iface);
g_clear_object (&impl->data_loop);
free (this->name);
g_clear_error (&impl->error);
if (this->properties)
pinos_properties_free (this->properties);
free (obj);
} }
PinosNode * PinosNode *
@ -551,31 +479,26 @@ pinos_node_new (PinosCore *core,
{ {
PinosNodeImpl *impl; PinosNodeImpl *impl;
PinosNode *this; PinosNode *this;
PinosObjectSkeleton *skel;
impl = calloc (1, sizeof (PinosNodeImpl)); impl = calloc (1, sizeof (PinosNodeImpl));
impl->core = core; this = &impl->this;
this = &impl->node; this->core = core;
pinos_log_debug ("node %p: new", this); pinos_log_debug ("node %p: new", this);
impl->ifaces[0].type = impl->core->registry.uri.node;
impl->ifaces[0].iface = this;
pinos_object_init (&impl->object,
node_destroy,
1,
impl->ifaces);
this->name = strdup (name); this->name = strdup (name);
this->properties = properties; this->properties = properties;
this->node = node; this->node = node;
this->clock = clock; this->clock = clock;
pinos_signal_init (&this->state_change); if (spa_node_set_event_callback (this->node, on_node_event, this) < 0)
pinos_signal_init (&this->port_added); pinos_log_warn ("node %p: error setting callback", this);
pinos_signal_init (&this->port_removed);
pinos_signal_init (&this->destroy_signal);
pinos_signal_init (&this->async_complete); pinos_signal_init (&this->async_complete);
pinos_signal_init (&this->transport_changed); pinos_signal_init (&this->transport_changed);
pinos_signal_init (&this->loop_changed);
impl->iface = pinos_node1_skeleton_new (); impl->iface = pinos_node1_skeleton_new ();
g_signal_connect (impl->iface, "handle-remove", g_signal_connect (impl->iface, "handle-remove",
@ -589,8 +512,6 @@ pinos_node_new (PinosCore *core,
//g_signal_connect (this, "notify", (GCallback) on_property_notify, this); //g_signal_connect (this, "notify", (GCallback) on_property_notify, this);
pinos_registry_add_object (&impl->core->registry, &impl->object);
if (this->node->info) { if (this->node->info) {
unsigned int i; unsigned int i;
@ -607,34 +528,53 @@ pinos_node_new (PinosCore *core,
init_complete (this); init_complete (this);
} else { } else {
impl->async_init = TRUE; impl->async_init = TRUE;
pinos_main_loop_defer (impl->core->main_loop, pinos_main_loop_defer (this->core->main_loop,
this, this,
SPA_RESULT_RETURN_ASYNC (0), SPA_RESULT_RETURN_ASYNC (0),
(PinosDeferFunc) init_complete, (PinosDeferFunc) init_complete,
NULL, NULL,
NULL); NULL);
} }
node_register_object (this); spa_list_insert (core->node_list.prev, &this->list);
skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_NODE);
pinos_object_skeleton_set_node1 (skel, impl->iface);
this->global = pinos_core_add_global (core,
core->registry.uri.node,
this,
skel);
return this; return this;
} }
/** /**
* pinos_node_get_daemon: * pinos_node_destroy:
* @node: a #PinosNode * @node: a #PinosNode
* *
* Get the daemon of @node. * Remove @node. This will stop the transfer on the node and
* * free the resources allocated by @node.
* Returns: the daemon of @node.
*/ */
PinosDaemon * void
pinos_node_get_daemon (PinosNode *node) pinos_node_destroy (PinosNode * this)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
g_return_val_if_fail (node, NULL); pinos_log_debug ("node %p: destroy", impl);
pinos_signal_emit (&this->destroy_signal, this);
return impl->daemon; pinos_node_set_state (this, PINOS_NODE_STATE_SUSPENDED);
spa_list_remove (&this->list);
pinos_core_remove_global (this->core, this->global);
pinos_main_loop_defer_cancel (this->core->main_loop, this, 0);
g_clear_object (&impl->iface);
free (this->name);
g_clear_error (&impl->error);
if (this->properties)
pinos_properties_free (this->properties);
free (impl);
} }
/** /**
@ -648,47 +588,9 @@ pinos_node_get_daemon (PinosNode *node)
PinosClient * PinosClient *
pinos_node_get_client (PinosNode *node) pinos_node_get_client (PinosNode *node)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
g_return_val_if_fail (node, NULL);
return impl->client; return impl->client;
} }
/**
* pinos_node_get_object_path:
* @node: a #PinosNode
*
* Get the object path of @node.
*
* Returns: the object path of @node.
*/
const gchar *
pinos_node_get_object_path (PinosNode *node)
{
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
g_return_val_if_fail (node, NULL);
return impl->object_path;
}
/**
* pinos_node_destroy:
* @node: a #PinosNode
*
* Remove @node. This will stop the transfer on the node and
* free the resources allocated by @node.
*/
void
pinos_node_destroy (PinosNode *node)
{
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
g_return_if_fail (impl);
pinos_log_debug ("node %p: destroy", impl);
pinos_object_destroy (&impl->object);
}
/** /**
* pinos_node_get_free_port: * pinos_node_get_free_port:
@ -703,7 +605,7 @@ PinosPort *
pinos_node_get_free_port (PinosNode *node, pinos_node_get_free_port (PinosNode *node,
PinosDirection direction) PinosDirection direction)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
guint free_port, n_ports, max_ports; guint free_port, n_ports, max_ports;
GList *ports, *walk; GList *ports, *walk;
PinosPort *port = NULL; PinosPort *port = NULL;
@ -751,7 +653,7 @@ do_add_link (SpaPoll *poll,
void *user_data) void *user_data)
{ {
PinosNode *this = user_data; PinosNode *this = user_data;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
PinosLink *link = ((PinosLink**)data)[0]; PinosLink *link = ((PinosLink**)data)[0];
g_ptr_array_add (impl->rt.links, link); g_ptr_array_add (impl->rt.links, link);
@ -812,9 +714,9 @@ pinos_port_link (PinosPort *output_port,
g_return_val_if_fail (input_port != NULL, NULL); g_return_val_if_fail (input_port != NULL, NULL);
output_node = output_port->node; output_node = output_port->node;
output_impl = SPA_CONTAINER_OF (output_node, PinosNodeImpl, node); output_impl = SPA_CONTAINER_OF (output_node, PinosNodeImpl, this);
input_node = input_port->node; input_node = input_port->node;
input_impl = SPA_CONTAINER_OF (input_node, PinosNodeImpl, node); input_impl = SPA_CONTAINER_OF (input_node, PinosNodeImpl, this);
pinos_log_debug ("port link %p:%u -> %p:%u", output_node, output_port->port, input_node, input_port->port); pinos_log_debug ("port link %p:%u -> %p:%u", output_node, output_port->port, input_node, input_port->port);
@ -826,15 +728,13 @@ pinos_port_link (PinosPort *output_port,
link = find_link (output_port, input_port); link = find_link (output_port, input_port);
if (link) { if (link == NULL) {
g_object_ref (link);
} else {
input_node->live = output_node->live; input_node->live = output_node->live;
if (output_node->clock) if (output_node->clock)
input_node->clock = output_node->clock; input_node->clock = output_node->clock;
pinos_log_debug ("node %p: clock %p, live %d", output_node, output_node->clock, output_node->live); pinos_log_debug ("node %p: clock %p, live %d", output_node, output_node->clock, output_node->live);
link = pinos_link_new (output_impl->core, link = pinos_link_new (output_node->core,
output_port, output_port,
input_port, input_port,
format_filter, format_filter,
@ -846,13 +746,13 @@ pinos_port_link (PinosPort *output_port,
output_impl->n_used_output_links++; output_impl->n_used_output_links++;
input_impl->n_used_input_links++; input_impl->n_used_input_links++;
spa_poll_invoke (&output_impl->data_loop->poll, spa_poll_invoke (&output_node->data_loop->poll,
do_add_link, do_add_link,
SPA_ID_INVALID, SPA_ID_INVALID,
sizeof (PinosLink *), sizeof (PinosLink *),
&link, &link,
output_node); output_node);
spa_poll_invoke (&input_impl->data_loop->poll, spa_poll_invoke (&input_node->data_loop->poll,
do_add_link, do_add_link,
SPA_ID_INVALID, SPA_ID_INVALID,
sizeof (PinosLink *), sizeof (PinosLink *),
@ -902,7 +802,7 @@ do_remove_link_done (SpaPoll *poll,
{ {
PinosPort *port = user_data; PinosPort *port = user_data;
PinosNode *this = port->node; PinosNode *this = port->node;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
PinosLink *link = ((PinosLink**)data)[0]; PinosLink *link = ((PinosLink**)data)[0];
pinos_log_debug ("port %p: finish unlink", port); pinos_log_debug ("port %p: finish unlink", port);
@ -931,7 +831,7 @@ do_remove_link_done (SpaPoll *poll,
port->n_buffers = 0; port->n_buffers = 0;
} }
pinos_main_loop_defer_complete (impl->core->main_loop, pinos_main_loop_defer_complete (this->core->main_loop,
port, port,
seq, seq,
SPA_RESULT_OK); SPA_RESULT_OK);
@ -951,7 +851,7 @@ do_remove_link (SpaPoll *poll,
{ {
PinosPort *port = user_data; PinosPort *port = user_data;
PinosNode *this = port->node; PinosNode *this = port->node;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this);
PinosLink *link = ((PinosLink**)data)[0]; PinosLink *link = ((PinosLink**)data)[0];
SpaResult res; SpaResult res;
@ -962,7 +862,7 @@ do_remove_link (SpaPoll *poll,
g_ptr_array_remove_fast (impl->rt.links, link); g_ptr_array_remove_fast (impl->rt.links, link);
res = spa_poll_invoke (impl->core->main_loop->poll, res = spa_poll_invoke (this->core->main_loop->poll,
do_remove_link_done, do_remove_link_done,
seq, seq,
sizeof (PinosLink *), sizeof (PinosLink *),
@ -975,13 +875,13 @@ SpaResult
pinos_port_unlink (PinosPort *port, PinosLink *link) pinos_port_unlink (PinosPort *port, PinosLink *link)
{ {
SpaResult res; SpaResult res;
PinosNodeImpl *impl = (PinosNodeImpl*)port->node; PinosNodeImpl *impl = SPA_CONTAINER_OF (port->node, PinosNodeImpl, this);
pinos_log_debug ("port %p: start unlink %p", port, link); pinos_log_debug ("port %p: start unlink %p", port, link);
g_object_ref (link); g_object_ref (link);
g_object_ref (port->node); g_object_ref (port->node);
res = spa_poll_invoke (&impl->data_loop->poll, res = spa_poll_invoke (&port->node->data_loop->poll,
do_remove_link, do_remove_link,
impl->seq++, impl->seq++,
sizeof (PinosLink *), sizeof (PinosLink *),
@ -1000,7 +900,6 @@ do_clear_buffers_done (SpaPoll *poll,
{ {
PinosPort *port = user_data; PinosPort *port = user_data;
PinosNode *this = port->node; PinosNode *this = port->node;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
SpaResult res; SpaResult res;
pinos_log_debug ("port %p: clear buffers finish", port); pinos_log_debug ("port %p: clear buffers finish", port);
@ -1012,7 +911,7 @@ do_clear_buffers_done (SpaPoll *poll,
port->buffers = NULL; port->buffers = NULL;
port->n_buffers = 0; port->n_buffers = 0;
pinos_main_loop_defer_complete (impl->core->main_loop, pinos_main_loop_defer_complete (this->core->main_loop,
port, port,
seq, seq,
res); res);
@ -1029,12 +928,11 @@ do_clear_buffers (SpaPoll *poll,
{ {
PinosPort *port = user_data; PinosPort *port = user_data;
PinosNode *this = port->node; PinosNode *this = port->node;
PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
SpaResult res; SpaResult res;
pinos_port_pause (port); pinos_port_pause (port);
res = spa_poll_invoke (impl->core->main_loop->poll, res = spa_poll_invoke (this->core->main_loop->poll,
do_clear_buffers_done, do_clear_buffers_done,
seq, seq,
0, NULL, 0, NULL,
@ -1046,10 +944,10 @@ SpaResult
pinos_port_clear_buffers (PinosPort *port) pinos_port_clear_buffers (PinosPort *port)
{ {
SpaResult res; SpaResult res;
PinosNodeImpl *impl = SPA_CONTAINER_OF (port->node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (port->node, PinosNodeImpl, this);
pinos_log_debug ("port %p: clear buffers", port); pinos_log_debug ("port %p: clear buffers", port);
res = spa_poll_invoke (&impl->data_loop->poll, res = spa_poll_invoke (&port->node->data_loop->poll,
do_clear_buffers, do_clear_buffers,
impl->seq++, impl->seq++,
0, NULL, 0, NULL,
@ -1070,7 +968,7 @@ GList *
pinos_node_get_ports (PinosNode *node, PinosDirection direction) pinos_node_get_ports (PinosNode *node, PinosDirection direction)
{ {
GList *ports; GList *ports;
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
g_return_val_if_fail (node, NULL); g_return_val_if_fail (node, NULL);
@ -1085,7 +983,7 @@ pinos_node_get_ports (PinosNode *node, PinosDirection direction)
static void static void
remove_idle_timeout (PinosNode *node) remove_idle_timeout (PinosNode *node)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
if (impl->idle_timeout) { if (impl->idle_timeout) {
g_source_remove (impl->idle_timeout); g_source_remove (impl->idle_timeout);
@ -1124,7 +1022,6 @@ SpaResult
pinos_node_set_state (PinosNode *node, pinos_node_set_state (PinosNode *node,
PinosNodeState state) PinosNodeState state)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
SpaResult res = SPA_RESULT_OK; SpaResult res = SPA_RESULT_OK;
g_return_val_if_fail (node, SPA_RESULT_INVALID_ARGUMENTS); g_return_val_if_fail (node, SPA_RESULT_INVALID_ARGUMENTS);
@ -1159,7 +1056,7 @@ pinos_node_set_state (PinosNode *node,
if (SPA_RESULT_IS_ERROR (res)) if (SPA_RESULT_IS_ERROR (res))
return res; return res;
pinos_main_loop_defer (impl->core->main_loop, pinos_main_loop_defer (node->core->main_loop,
node, node,
res, res,
(PinosDeferFunc) on_state_complete, (PinosDeferFunc) on_state_complete,
@ -1181,22 +1078,20 @@ void
pinos_node_update_state (PinosNode *node, pinos_node_update_state (PinosNode *node,
PinosNodeState state) PinosNodeState state)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
PinosNodeState old; PinosNodeState old;
g_return_if_fail (node); g_return_if_fail (node);
old = node->state; old = node->state;
if (old != state) { if (old != state) {
PinosNodeStateChangeData sc = { old, state };
pinos_log_debug ("node %p: update state from %s -> %s", node, pinos_log_debug ("node %p: update state from %s -> %s", node,
pinos_node_state_as_string (old), pinos_node_state_as_string (old),
pinos_node_state_as_string (state)); pinos_node_state_as_string (state));
node->state = state; node->state = state;
pinos_node1_set_state (impl->iface, state); pinos_node1_set_state (impl->iface, state);
pinos_signal_emit (&node->state_change, node, &sc); pinos_signal_emit (&node->core->node_state_changed, node, old, state);
} }
} }
@ -1211,25 +1106,25 @@ void
pinos_node_report_error (PinosNode *node, pinos_node_report_error (PinosNode *node,
GError *error) GError *error)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
PinosNodeStateChangeData sc; PinosNodeState old;
g_return_if_fail (node); g_return_if_fail (node);
g_clear_error (&impl->error); g_clear_error (&impl->error);
remove_idle_timeout (node); remove_idle_timeout (node);
impl->error = error; impl->error = error;
sc.old = node->state; old = node->state;
sc.state = node->state = PINOS_NODE_STATE_ERROR; node->state = PINOS_NODE_STATE_ERROR;
pinos_log_debug ("node %p: got error state %s", node, error->message); pinos_log_debug ("node %p: got error state %s", node, error->message);
pinos_node1_set_state (impl->iface, PINOS_NODE_STATE_ERROR); pinos_node1_set_state (impl->iface, PINOS_NODE_STATE_ERROR);
pinos_signal_emit (&node->state_change, node, &sc); pinos_signal_emit (&node->core->node_state_changed, node, old, node->state);
} }
static gboolean static gboolean
idle_timeout (PinosNode *node) idle_timeout (PinosNode *node)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
impl->idle_timeout = 0; impl->idle_timeout = 0;
pinos_log_debug ("node %p: idle timeout", node); pinos_log_debug ("node %p: idle timeout", node);
@ -1248,7 +1143,7 @@ idle_timeout (PinosNode *node)
void void
pinos_node_report_idle (PinosNode *node) pinos_node_report_idle (PinosNode *node)
{ {
PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node); PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
g_return_if_fail (node); g_return_if_fail (node);

View file

@ -27,11 +27,8 @@ G_BEGIN_DECLS
#define PINOS_NODE_URI "http://pinos.org/ns/node" #define PINOS_NODE_URI "http://pinos.org/ns/node"
#define PINOS_NODE_PREFIX PINOS_NODE_URI "#" #define PINOS_NODE_PREFIX PINOS_NODE_URI "#"
#define PINOS_PORT_URI PINOS_NODE_PREFIX "Port"
typedef struct _PinosPort PinosPort; typedef struct _PinosPort PinosPort;
typedef struct _PinosNode PinosNode; typedef struct _PinosNode PinosNode;
typedef struct _PinosNodeListener PinosNodeListener;
#include <spa/include/spa/node.h> #include <spa/include/spa/node.h>
@ -42,9 +39,10 @@ typedef struct _PinosNodeListener PinosNodeListener;
#include <pinos/server/daemon.h> #include <pinos/server/daemon.h>
#include <pinos/server/link.h> #include <pinos/server/link.h>
#include <pinos/server/client.h> #include <pinos/server/client.h>
#include <pinos/server/data-loop.h>
struct _PinosPort { struct _PinosPort {
PinosObject object; PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosPort *));
PinosNode *node; PinosNode *node;
PinosDirection direction; PinosDirection direction;
@ -74,12 +72,16 @@ typedef struct {
* Pinos node class. * Pinos node class.
*/ */
struct _PinosNode { struct _PinosNode {
PinosCore *core;
SpaList list;
PinosGlobal *global;
char *name; char *name;
PinosProperties *properties; PinosProperties *properties;
PinosNodeState state; PinosNodeState state;
SpaHandle *handle;
SpaNode *node; SpaNode *node;
bool live; bool live;
SpaClock *clock; SpaClock *clock;
@ -87,12 +89,20 @@ struct _PinosNode {
gboolean have_outputs; gboolean have_outputs;
PinosTransport *transport; PinosTransport *transport;
PinosSignal transport_changed; PINOS_SIGNAL (transport_changed, (PinosListener *listener,
PinosNode *object));
PinosSignal state_change; PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
PinosSignal port_added; PinosNode *object));
PinosSignal port_removed;
PinosSignal async_complete; PINOS_SIGNAL (async_complete, (PinosListener *listener,
PinosNode *node,
uint32_t seq,
SpaResult res));
PinosDataLoop *data_loop;
PINOS_SIGNAL (loop_changed, (PinosListener *listener,
PinosNode *object));
PinosPort * (*get_free_port) (PinosNode *node, PinosPort * (*get_free_port) (PinosNode *node,
PinosDirection direction); PinosDirection direction);
@ -103,37 +113,18 @@ struct _PinosNode {
PinosNodeState state); PinosNodeState state);
}; };
struct _PinosNodeListener { PinosNode * pinos_node_new (PinosCore *core,
void (*async_complete) (PinosNodeListener *listener,
PinosNode *node,
uint32_t seq,
SpaResult res);
void (*state_change) (PinosNodeListener *listener,
PinosNode *node,
PinosNodeState old,
PinosNodeState state);
void (*port_added) (PinosNodeListener *listener,
PinosNode *node,
PinosPort *port);
void (*port_removed) (PinosNodeListener *listener,
PinosNode *node,
PinosPort *port);
};
PinosObject * pinos_node_new (PinosCore *core,
const char *name, const char *name,
SpaNode *node, SpaNode *node,
SpaClock *clock, SpaClock *clock,
PinosProperties *properties); PinosProperties *properties);
void pinos_node_destroy (PinosNode *node);
void pinos_node_set_data_loop (PinosNode *node,
PinosDataLoop *loop);
PinosDaemon * pinos_node_get_daemon (PinosNode *node);
PinosClient * pinos_node_get_client (PinosNode *node); PinosClient * pinos_node_get_client (PinosNode *node);
const gchar * pinos_node_get_object_path (PinosNode *node);
PinosPort * pinos_node_get_free_port (PinosNode *node, PinosPort * pinos_node_get_free_port (PinosNode *node,
PinosDirection direction); PinosDirection direction);

View file

@ -34,13 +34,11 @@ pinos_registry_init (PinosRegistry *reg)
{ {
reg->map = pinos_id_map_get_default(); reg->map = pinos_id_map_get_default();
reg->uri.core = spa_id_map_get_id (reg->map, PINOS_CORE_URI);
reg->uri.daemon = spa_id_map_get_id (reg->map, PINOS_DAEMON_URI); reg->uri.daemon = spa_id_map_get_id (reg->map, PINOS_DAEMON_URI);
reg->uri.registry = spa_id_map_get_id (reg->map, PINOS_REGISTRY_URI); reg->uri.registry = spa_id_map_get_id (reg->map, PINOS_REGISTRY_URI);
reg->uri.node = spa_id_map_get_id (reg->map, PINOS_NODE_URI); reg->uri.node = spa_id_map_get_id (reg->map, PINOS_NODE_URI);
reg->uri.port = spa_id_map_get_id (reg->map, PINOS_PORT_URI);
reg->uri.link = spa_id_map_get_id (reg->map, PINOS_LINK_URI);
reg->uri.node_factory = spa_id_map_get_id (reg->map, PINOS_NODE_FACTORY_URI); reg->uri.node_factory = spa_id_map_get_id (reg->map, PINOS_NODE_FACTORY_URI);
reg->uri.link = spa_id_map_get_id (reg->map, PINOS_LINK_URI);
reg->uri.client = spa_id_map_get_id (reg->map, PINOS_CLIENT_URI); reg->uri.client = spa_id_map_get_id (reg->map, PINOS_CLIENT_URI);
reg->uri.spa_node = spa_id_map_get_id (reg->map, SPA_NODE_URI); reg->uri.spa_node = spa_id_map_get_id (reg->map, SPA_NODE_URI);
@ -48,9 +46,6 @@ pinos_registry_init (PinosRegistry *reg)
reg->uri.spa_monitor = spa_id_map_get_id (reg->map, SPA_MONITOR_URI); reg->uri.spa_monitor = spa_id_map_get_id (reg->map, SPA_MONITOR_URI);
pinos_map_init (&reg->objects, 512); pinos_map_init (&reg->objects, 512);
pinos_signal_init (&reg->object_added);
pinos_signal_init (&reg->object_removed);
} }
PinosObject * PinosObject *
@ -65,7 +60,7 @@ pinos_registry_iterate_objects (PinosRegistry *reg,
idx = SPA_PTR_TO_INT (*state); idx = SPA_PTR_TO_INT (*state);
*state = SPA_INT_TO_PTR (idx+1); *state = SPA_INT_TO_PTR (idx+1);
o = pinos_map_lookup (&reg->objects, idx); o = pinos_map_lookup (&reg->objects, idx);
if (o != NULL && (type == SPA_ID_INVALID || o->type == type)) if (o != NULL)
break; break;
} }
return o; return o;

View file

@ -35,15 +35,13 @@ extern "C" {
typedef struct _PinosRegistry PinosRegistry; typedef struct _PinosRegistry PinosRegistry;
typedef struct { typedef struct {
uint32_t core;
uint32_t daemon; uint32_t daemon;
uint32_t registry; uint32_t registry;
uint32_t node; uint32_t node;
uint32_t port;
uint32_t link;
uint32_t node_factory; uint32_t node_factory;
uint32_t link;
uint32_t client; uint32_t client;
uint32_t monitor;
uint32_t spa_node; uint32_t spa_node;
uint32_t spa_clock; uint32_t spa_clock;
uint32_t spa_monitor; uint32_t spa_monitor;
@ -55,35 +53,13 @@ typedef struct {
* Pinos registry struct. * Pinos registry struct.
*/ */
struct _PinosRegistry { struct _PinosRegistry {
PinosObject object;
SpaIDMap *map; SpaIDMap *map;
PinosURI uri; PinosURI uri;
PinosMap objects; PinosMap objects;
PinosSignal object_added;
PinosSignal object_removed;
}; };
void pinos_registry_init (PinosRegistry *reg); void pinos_registry_init (PinosRegistry *reg);
static inline void
pinos_registry_add_object (PinosRegistry *reg,
PinosObject *object)
{
object->id = pinos_map_insert_new (&reg->objects, object);
pinos_signal_emit (&reg->object_added, reg, object);
}
static inline void
pinos_registry_remove_object (PinosRegistry *reg,
PinosObject *object)
{
pinos_signal_emit (&reg->object_removed, reg, object);
pinos_map_remove (&reg->objects, object->id);
}
PinosObject * pinos_registry_iterate_objects (PinosRegistry *reg, PinosObject * pinos_registry_iterate_objects (PinosRegistry *reg,
uint32_t type, uint32_t type,
void **state); void **state);

View file

@ -34,12 +34,13 @@ typedef enum {
SPA_RESULT_MODIFIED = 1, SPA_RESULT_MODIFIED = 1,
SPA_RESULT_OK = 0, SPA_RESULT_OK = 0,
SPA_RESULT_ERROR = -1, SPA_RESULT_ERROR = -1,
SPA_RESULT_INACTIVE = -2, SPA_RESULT_ERRNO = -2,
SPA_RESULT_NO_FORMAT = -3, SPA_RESULT_INACTIVE = -3,
SPA_RESULT_INVALID_COMMAND = -4, SPA_RESULT_NO_FORMAT = -4,
SPA_RESULT_INVALID_PORT = -5, SPA_RESULT_INVALID_COMMAND = -5,
SPA_RESULT_HAVE_ENOUGH_INPUT = -6, SPA_RESULT_INVALID_PORT = -6,
SPA_RESULT_NEED_MORE_INPUT = -7, SPA_RESULT_HAVE_ENOUGH_INPUT = -7,
SPA_RESULT_NEED_MORE_INPUT = -8,
SPA_RESULT_PORTS_CHANGED = -9, SPA_RESULT_PORTS_CHANGED = -9,
SPA_RESULT_FORMAT_CHANGED = -10, SPA_RESULT_FORMAT_CHANGED = -10,
SPA_RESULT_PROPERTIES_CHANGED = -11, SPA_RESULT_PROPERTIES_CHANGED = -11,

View file

@ -515,6 +515,7 @@ spa_v4l2_source_node_port_enum_formats (SpaNode *node,
this = SPA_CONTAINER_OF (node, SpaV4l2Source, node); this = SPA_CONTAINER_OF (node, SpaV4l2Source, node);
spa_log_debug (this->log, "%p %d %d", this, direction, port_id);
if (!CHECK_PORT (this, direction, port_id)) if (!CHECK_PORT (this, direction, port_id))
return SPA_RESULT_INVALID_PORT; return SPA_RESULT_INVALID_PORT;