mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	WIP change object model
This commit is contained in:
		
							parent
							
								
									190f01d88e
								
							
						
					
					
						commit
						c25ccbb4ba
					
				
					 44 changed files with 1557 additions and 2525 deletions
				
			
		| 
						 | 
				
			
			@ -112,6 +112,9 @@ pinos_array_add_fixed (PinosArray *arr,
 | 
			
		|||
  return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define pinos_array_add_ptr(a,p)                                \
 | 
			
		||||
  *((void**) pinos_array_add (a, sizeof (void*))) = (p)
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}  /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ pinos_headers = [
 | 
			
		|||
  'subscribe.h',
 | 
			
		||||
  'thread-mainloop.h',
 | 
			
		||||
  'transport.h',
 | 
			
		||||
  'utils.h',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
pinos_sources = [
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +34,7 @@ pinos_sources = [
 | 
			
		|||
  'subscribe.c',
 | 
			
		||||
  'thread-mainloop.c',
 | 
			
		||||
  'transport.c',
 | 
			
		||||
  'utils.c',
 | 
			
		||||
  gdbus_target,
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,7 +47,8 @@ struct _PinosObject {
 | 
			
		|||
  uint32_t          id;
 | 
			
		||||
  PinosObjectFlags  flags;
 | 
			
		||||
  PinosDestroyFunc  destroy;
 | 
			
		||||
  PinosSignal       destroy_signal;
 | 
			
		||||
  PINOS_SIGNAL      (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                      PinosObject   *object));
 | 
			
		||||
  unsigned int      n_interfaces;
 | 
			
		||||
  PinosInterface   *interfaces;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +82,7 @@ static inline void
 | 
			
		|||
pinos_object_destroy (PinosObject *object)
 | 
			
		||||
{
 | 
			
		||||
  object->flags |= PINOS_OBJECT_FLAG_DESTROYING;
 | 
			
		||||
  pinos_signal_emit (&object->destroy_signal, object, NULL);
 | 
			
		||||
  pinos_signal_emit (&object->destroy_signal, object);
 | 
			
		||||
  if (object->destroy)
 | 
			
		||||
    object->destroy (object);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,7 @@ extern const char             g_log_domain_pinos[];
 | 
			
		|||
#include <pinos/client/ringbuffer.h>
 | 
			
		||||
#include <pinos/client/stream.h>
 | 
			
		||||
#include <pinos/client/subscribe.h>
 | 
			
		||||
#include <pinos/client/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/id-map.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,25 +31,31 @@ typedef struct _PinosListener PinosListener;
 | 
			
		|||
 | 
			
		||||
struct _PinosListener {
 | 
			
		||||
  SpaList         link;
 | 
			
		||||
  void (*notify) (PinosListener *listener, void *object, void *data);
 | 
			
		||||
  void (*notify) (void *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
struct _PinosSignal {
 | 
			
		||||
  SpaList listeners;
 | 
			
		||||
  void (*notify) (PinosListener *listener, void *object, void *data);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_signal_init (PinosSignal *signal)
 | 
			
		||||
{
 | 
			
		||||
  spa_list_init (&signal->listeners);
 | 
			
		||||
}
 | 
			
		||||
#define PINOS_SIGNAL(name,func)                    \
 | 
			
		||||
  union {                                               \
 | 
			
		||||
    SpaList listeners;                                  \
 | 
			
		||||
    void (*notify) func;                           \
 | 
			
		||||
  } name;
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_signal_add (PinosSignal   *signal,
 | 
			
		||||
                  PinosListener *listener)
 | 
			
		||||
{
 | 
			
		||||
  spa_list_insert (signal->listeners.prev, &listener->link);
 | 
			
		||||
}
 | 
			
		||||
#define pinos_signal_init(signal)                       \
 | 
			
		||||
  spa_list_init (&(signal)->listeners);
 | 
			
		||||
 | 
			
		||||
#define pinos_signal_add(signal,listener,func)                          \
 | 
			
		||||
  do {                                                                  \
 | 
			
		||||
    __typeof__((signal)->notify) n = (func);                             \
 | 
			
		||||
    (listener)->notify = (void (*) (void *)) n;                                             \
 | 
			
		||||
    spa_list_insert ((signal)->listeners.prev, &(listener)->link);      \
 | 
			
		||||
  } while (false);
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_signal_remove (PinosListener *listener)
 | 
			
		||||
| 
						 | 
				
			
			@ -57,16 +63,12 @@ pinos_signal_remove (PinosListener *listener)
 | 
			
		|||
  spa_list_remove (&listener->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_signal_emit (PinosSignal *signal,
 | 
			
		||||
                   void        *object,
 | 
			
		||||
                   void        *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosListener *l, *next;
 | 
			
		||||
 | 
			
		||||
  spa_list_for_each_safe (l, next, &signal->listeners, link)
 | 
			
		||||
    l->notify (l, object, data);
 | 
			
		||||
}
 | 
			
		||||
#define pinos_signal_emit(signal,...)                                   \
 | 
			
		||||
  do {                                                                  \
 | 
			
		||||
    PinosListener *l, *next;                                            \
 | 
			
		||||
    spa_list_for_each_safe (l, next, &(signal)->listeners, link)        \
 | 
			
		||||
      ((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__);       \
 | 
			
		||||
  } while (false);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										83
									
								
								pinos/client/utils.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pinos/client/utils.c
									
										
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/* Pinos
 | 
			
		||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
			
		||||
/* 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
 | 
			
		||||
| 
						 | 
				
			
			@ -17,26 +17,29 @@
 | 
			
		|||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PINOS_SPA_ALSA_MONITOR_H__
 | 
			
		||||
#define __PINOS_SPA_ALSA_MONITOR_H__
 | 
			
		||||
#ifndef __PINOS_UTILS_H__
 | 
			
		||||
#define __PINOS_UTILS_H__
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <spa/defs.h>
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/monitor.h>
 | 
			
		||||
#include <pinos/server/daemon.h>
 | 
			
		||||
const char * pinos_split_walk   (const char  *str,
 | 
			
		||||
                                 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 {
 | 
			
		||||
  SpaMonitor *monitor;
 | 
			
		||||
};
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}  /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PinosSpaALSAMonitor *         pinos_spa_alsa_monitor_new      (PinosCore *core);
 | 
			
		||||
void                          pinos_spa_alsa_monitor_destroy  (PinosSpaALSAMonitor *monitor);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
#endif /* __PINOS_SPA_ALSA_MONITOR_H__ */
 | 
			
		||||
#endif /* __PINOS_UTILS_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,6 @@
 | 
			
		|||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/pinos.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -32,29 +31,17 @@
 | 
			
		|||
 | 
			
		||||
#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf"
 | 
			
		||||
 | 
			
		||||
GQuark
 | 
			
		||||
pinos_daemon_config_error_quark (void)
 | 
			
		||||
{
 | 
			
		||||
  static GQuark quark = 0;
 | 
			
		||||
 | 
			
		||||
  if (quark == 0) {
 | 
			
		||||
    quark = g_quark_from_static_string ("pinos_daemon_config_error");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return quark;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
static bool
 | 
			
		||||
parse_line (PinosDaemonConfig  *config,
 | 
			
		||||
            const gchar        * filename,
 | 
			
		||||
            gchar              * line,
 | 
			
		||||
            guint                lineno,
 | 
			
		||||
            GError            ** err)
 | 
			
		||||
            const char         *filename,
 | 
			
		||||
            char               *line,
 | 
			
		||||
            unsigned int        lineno,
 | 
			
		||||
            char              **err)
 | 
			
		||||
{
 | 
			
		||||
  PinosCommand *command = NULL;
 | 
			
		||||
  gchar *p;
 | 
			
		||||
  gboolean ret = TRUE;
 | 
			
		||||
  GError *local_err = NULL;
 | 
			
		||||
  char *p;
 | 
			
		||||
  bool ret = true;
 | 
			
		||||
  char *local_err = NULL;
 | 
			
		||||
 | 
			
		||||
  /* search for comments */
 | 
			
		||||
  if ((p = strchr (line, '#')))
 | 
			
		||||
| 
						 | 
				
			
			@ -64,16 +51,14 @@ parse_line (PinosDaemonConfig  * config,
 | 
			
		|||
  g_strstrip (line);
 | 
			
		||||
 | 
			
		||||
  if (*line == '\0') /* empty line */
 | 
			
		||||
    return TRUE;
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  if (!pinos_command_parse (&command, line, &local_err)) {
 | 
			
		||||
    g_set_error (err, PINOS_DAEMON_CONFIG_ERROR,
 | 
			
		||||
        PINOS_DAEMON_CONFIG_ERROR_COMMAND, "%s:%u: %s", filename, lineno,
 | 
			
		||||
        local_err->message);
 | 
			
		||||
    g_error_free (local_err);
 | 
			
		||||
    ret = FALSE;
 | 
			
		||||
  if ((command = pinos_command_parse (line, &local_err)) == NULL) {
 | 
			
		||||
    asprintf (err, "%s:%u: %s", filename, lineno, local_err);
 | 
			
		||||
    free (local_err);
 | 
			
		||||
    ret = false;
 | 
			
		||||
  } else {
 | 
			
		||||
    config->commands = g_list_append (config->commands, command);
 | 
			
		||||
    spa_list_insert (config->commands.prev, &command->link);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -89,9 +74,8 @@ pinos_daemon_config_new (void)
 | 
			
		|||
{
 | 
			
		||||
  PinosDaemonConfig *config;
 | 
			
		||||
 | 
			
		||||
  config = g_new (PinosDaemonConfig, 1);
 | 
			
		||||
 | 
			
		||||
  config->commands = NULL;
 | 
			
		||||
  config = calloc (1, sizeof (PinosDaemonConfig));
 | 
			
		||||
  spa_list_init (&config->commands);
 | 
			
		||||
 | 
			
		||||
  return config;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -105,52 +89,50 @@ pinos_daemon_config_new (void)
 | 
			
		|||
void
 | 
			
		||||
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:
 | 
			
		||||
 * @config: A #PinosDaemonConfig
 | 
			
		||||
 * @filename: A filename
 | 
			
		||||
 * @err: Return location for a #GError, or %NULL
 | 
			
		||||
 * @err: Return location for an error string
 | 
			
		||||
 *
 | 
			
		||||
 * 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,
 | 
			
		||||
                               const gchar        * filename,
 | 
			
		||||
                               GError            ** err)
 | 
			
		||||
                               const char        *filename,
 | 
			
		||||
                               char             **err)
 | 
			
		||||
{
 | 
			
		||||
  gchar *data;
 | 
			
		||||
  gchar **lines;
 | 
			
		||||
  gboolean ret = TRUE;
 | 
			
		||||
  guint i;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (config != NULL, FALSE);
 | 
			
		||||
  g_return_val_if_fail (filename != NULL && *filename != '\0', FALSE);
 | 
			
		||||
  char *data;
 | 
			
		||||
  char **lines;
 | 
			
		||||
  bool ret = true;
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
  int n_lines;
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("deamon-config %p loading file %s", config, filename);
 | 
			
		||||
 | 
			
		||||
  if (!g_file_get_contents (filename, &data, NULL, err)) {
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
  if (!g_file_get_contents (filename, &data, NULL, NULL))
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  lines = g_strsplit (data, "\n", 0);
 | 
			
		||||
  lines = pinos_split_strv (data, "\n", 0, &n_lines);
 | 
			
		||||
  for (i = 0; lines[i] != NULL; i++) {
 | 
			
		||||
    if (!parse_line (config, filename, lines[i], i+1, err)) {
 | 
			
		||||
      ret = FALSE;
 | 
			
		||||
      ret = false;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  g_strfreev (lines);
 | 
			
		||||
  g_free (data);
 | 
			
		||||
  pinos_free_strv (lines);
 | 
			
		||||
  free (data);
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 * 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,
 | 
			
		||||
                          GError            ** err)
 | 
			
		||||
                          char              **err)
 | 
			
		||||
{
 | 
			
		||||
  const gchar *filename;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (config != NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  filename = g_getenv ("PINOS_CONFIG_FILE");
 | 
			
		||||
  filename = getenv ("PINOS_CONFIG_FILE");
 | 
			
		||||
  if (filename != NULL && *filename != '\0') {
 | 
			
		||||
    pinos_log_debug ("PINOS_CONFIG_FILE set to: %s", filename);
 | 
			
		||||
  } else {
 | 
			
		||||
    filename = DEFAULT_CONFIG_FILE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 * 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,
 | 
			
		||||
                                  PinosDaemon        *daemon)
 | 
			
		||||
{
 | 
			
		||||
  GList *walk;
 | 
			
		||||
  GError *err = NULL;
 | 
			
		||||
  gboolean ret = TRUE;
 | 
			
		||||
  char *err = NULL;
 | 
			
		||||
  bool ret = true;
 | 
			
		||||
  PinosCommand *command, *tmp;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (config != NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
  for (walk = config->commands; walk != NULL; walk = walk->next) {
 | 
			
		||||
    PinosCommand *command = (PinosCommand *)walk->data;
 | 
			
		||||
  spa_list_for_each (command, &config->commands, link) {
 | 
			
		||||
    if (!pinos_command_run (command, daemon->core, &err)) {
 | 
			
		||||
      pinos_log_warn ("could not run command %s: %s",
 | 
			
		||||
          pinos_command_get_name (command), err->message);
 | 
			
		||||
      g_clear_error (&err);
 | 
			
		||||
      ret = FALSE;
 | 
			
		||||
      pinos_log_warn ("could not run command %s: %s", command->name, err);
 | 
			
		||||
      free (err);
 | 
			
		||||
      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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,47 +27,20 @@ G_BEGIN_DECLS
 | 
			
		|||
 | 
			
		||||
#include <pinos/server/daemon.h>
 | 
			
		||||
 | 
			
		||||
#define PINOS_TYPE_DAEMON_CONFIG           (pinos_daemon_config_get_type ())
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosDaemonConfig 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);
 | 
			
		||||
void                pinos_daemon_config_free          (PinosDaemonConfig  *config);
 | 
			
		||||
gboolean            pinos_daemon_config_load_file     (PinosDaemonConfig  *config,
 | 
			
		||||
                                                       const gchar        *filename,
 | 
			
		||||
                                                       GError            **err);
 | 
			
		||||
gboolean            pinos_daemon_config_load          (PinosDaemonConfig  *config,
 | 
			
		||||
                                                       GError            **err);
 | 
			
		||||
gboolean            pinos_daemon_config_run_commands  (PinosDaemonConfig  *config,
 | 
			
		||||
bool                pinos_daemon_config_load_file     (PinosDaemonConfig  *config,
 | 
			
		||||
                                                       const char         *filename,
 | 
			
		||||
                                                       char              **err);
 | 
			
		||||
bool                pinos_daemon_config_load          (PinosDaemonConfig  *config,
 | 
			
		||||
                                                       char              **err);
 | 
			
		||||
bool                pinos_daemon_config_run_commands  (PinosDaemonConfig  *config,
 | 
			
		||||
                                                       PinosDaemon        *daemon);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,24 +17,21 @@
 | 
			
		|||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/pinos.h>
 | 
			
		||||
#include <pinos/server/daemon.h>
 | 
			
		||||
#include <pinos/server/module.h>
 | 
			
		||||
 | 
			
		||||
#include "daemon-config.h"
 | 
			
		||||
 | 
			
		||||
gint
 | 
			
		||||
main (gint argc, gchar *argv[])
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  PinosDaemon *daemon;
 | 
			
		||||
  PinosMainLoop *loop;
 | 
			
		||||
  PinosDaemonConfig *config;
 | 
			
		||||
  PinosProperties *props;
 | 
			
		||||
  GError *err = NULL;
 | 
			
		||||
  char *err = NULL;
 | 
			
		||||
 | 
			
		||||
  pinos_init (&argc, &argv);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +41,8 @@ main (gint argc, gchar *argv[])
 | 
			
		|||
  /* parse configuration */
 | 
			
		||||
  config = pinos_daemon_config_new ();
 | 
			
		||||
  if (!pinos_daemon_config_load (config, &err)) {
 | 
			
		||||
    g_error ("failed to parse config: %s", err->message);
 | 
			
		||||
    g_clear_error (&err);
 | 
			
		||||
    g_error ("failed to parse config: %s", err);
 | 
			
		||||
    free (err);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  props = pinos_properties_new ("test", "test", NULL);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,12 @@
 | 
			
		|||
pinos_module_spa_headers = [
 | 
			
		||||
  'spa-alsa-monitor.h',
 | 
			
		||||
  'spa-audiotestsrc.h',
 | 
			
		||||
  'spa-v4l2-monitor.h',
 | 
			
		||||
  'spa-videotestsrc.h',
 | 
			
		||||
  'spa-node.h',
 | 
			
		||||
  'spa-monitor.h',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
pinos_module_spa_sources = [
 | 
			
		||||
  'module.c',
 | 
			
		||||
  'spa-alsa-monitor.c',
 | 
			
		||||
  'spa-audiotestsrc.c',
 | 
			
		||||
  'spa-v4l2-monitor.c',
 | 
			
		||||
  'spa-videotestsrc.c',
 | 
			
		||||
  'spa-node.c',
 | 
			
		||||
  'spa-monitor.c',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
pinos_module_spa_c_args = [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,20 +21,26 @@
 | 
			
		|||
#include <server/daemon.h>
 | 
			
		||||
#include <server/module.h>
 | 
			
		||||
 | 
			
		||||
#include "spa-alsa-monitor.h"
 | 
			
		||||
#include "spa-v4l2-monitor.h"
 | 
			
		||||
#include "spa-audiotestsrc.h"
 | 
			
		||||
#include "spa-videotestsrc.h"
 | 
			
		||||
#include "spa-monitor.h"
 | 
			
		||||
#include "spa-node.h"
 | 
			
		||||
 | 
			
		||||
gboolean pinos__module_init (PinosModule *module, const gchar * args);
 | 
			
		||||
bool pinos__module_init (PinosModule *module, const char * args);
 | 
			
		||||
 | 
			
		||||
G_MODULE_EXPORT gboolean
 | 
			
		||||
pinos__module_init (PinosModule * module, G_GNUC_UNUSED const gchar * args)
 | 
			
		||||
G_MODULE_EXPORT bool
 | 
			
		||||
pinos__module_init (PinosModule * module, const char * args)
 | 
			
		||||
{
 | 
			
		||||
  pinos_spa_alsa_monitor_new (module->core);
 | 
			
		||||
  pinos_spa_v4l2_monitor_new (module->core);
 | 
			
		||||
  pinos_spa_audiotestsrc_new (module->core, "audiotestsrc", NULL);
 | 
			
		||||
  pinos_spa_videotestsrc_new (module->core, "videotestsrc", NULL);
 | 
			
		||||
  pinos_spa_monitor_load (module->core, "build/spa/plugins/alsa/libspa-alsa.so", "alsa-monitor", args);
 | 
			
		||||
  pinos_spa_monitor_load (module->core, "build/spa/plugins/v4l2/libspa-v4l2.so", "v4l2-monitor", args);
 | 
			
		||||
  pinos_spa_node_load (module->core,
 | 
			
		||||
                       "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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -31,70 +31,23 @@
 | 
			
		|||
#include <pinos/client/log.h>
 | 
			
		||||
#include <pinos/server/node.h>
 | 
			
		||||
 | 
			
		||||
#include "spa-v4l2-monitor.h"
 | 
			
		||||
#include "spa-monitor.h"
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosSpaV4l2Monitor this;
 | 
			
		||||
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosSpaMonitor this;
 | 
			
		||||
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
 | 
			
		||||
  SpaHandle *handle;
 | 
			
		||||
  void *hnd;
 | 
			
		||||
 | 
			
		||||
  GHashTable *nodes;
 | 
			
		||||
} PinosSpaV4l2MonitorImpl;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
} PinosSpaMonitorImpl;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
  SpaHandle *handle;
 | 
			
		||||
  PinosNode *node;
 | 
			
		||||
| 
						 | 
				
			
			@ -102,7 +55,7 @@ add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item)
 | 
			
		|||
  void *clock_iface;
 | 
			
		||||
  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);
 | 
			
		||||
  if ((res = spa_handle_factory_init (item->factory,
 | 
			
		||||
| 
						 | 
				
			
			@ -143,12 +96,12 @@ add_item (PinosSpaV4l2Monitor *this, SpaMonitorItem *item)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  if (node) {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +115,7 @@ on_monitor_event  (SpaMonitor      *monitor,
 | 
			
		|||
                   SpaMonitorEvent *event,
 | 
			
		||||
                   void            *user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosSpaV4l2Monitor *this = user_data;
 | 
			
		||||
  PinosSpaMonitor *this = user_data;
 | 
			
		||||
 | 
			
		||||
  switch (event->type) {
 | 
			
		||||
    case SPA_MONITOR_EVENT_TYPE_ADDED:
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +132,7 @@ on_monitor_event  (SpaMonitor      *monitor,
 | 
			
		|||
    case SPA_MONITOR_EVENT_TYPE_CHANGED:
 | 
			
		||||
    {
 | 
			
		||||
      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;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
| 
						 | 
				
			
			@ -187,64 +140,74 @@ on_monitor_event  (SpaMonitor      *monitor,
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
monitor_destroy (PinosObject * object)
 | 
			
		||||
PinosSpaMonitor *
 | 
			
		||||
pinos_spa_monitor_load (PinosCore  *core,
 | 
			
		||||
                        const char *lib,
 | 
			
		||||
                        const char *factory_name,
 | 
			
		||||
                        const char *args)
 | 
			
		||||
{
 | 
			
		||||
  PinosSpaV4l2MonitorImpl *impl = SPA_CONTAINER_OF (object, PinosSpaV4l2MonitorImpl, object);
 | 
			
		||||
  PinosSpaV4l2Monitor *this = &impl->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;
 | 
			
		||||
  PinosSpaMonitorImpl *impl;
 | 
			
		||||
  PinosSpaMonitor *this;
 | 
			
		||||
  SpaHandle *handle;
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
  void *iface;
 | 
			
		||||
  void *state = NULL;
 | 
			
		||||
  void *hnd, *state = NULL;
 | 
			
		||||
  SpaEnumHandleFactoryFunc enum_func;
 | 
			
		||||
  const SpaHandleFactory *factory;
 | 
			
		||||
 | 
			
		||||
  if ((res = make_handle (core,
 | 
			
		||||
                          &handle,
 | 
			
		||||
                          "build/spa/plugins/v4l2/libspa-v4l2.so",
 | 
			
		||||
                          "v4l2-monitor",
 | 
			
		||||
                          NULL)) < 0) {
 | 
			
		||||
    pinos_log_error ("can't create v4l2-monitor: %d", res);
 | 
			
		||||
  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_monitor,
 | 
			
		||||
                                       &iface)) < 0) {
 | 
			
		||||
    free (handle);
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
  pinos_object_init (&impl->object,
 | 
			
		||||
                     core->registry.uri.monitor,
 | 
			
		||||
                     impl,
 | 
			
		||||
                     monitor_destroy);
 | 
			
		||||
  impl->hnd = hnd;
 | 
			
		||||
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
  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,
 | 
			
		||||
                                       g_str_equal,
 | 
			
		||||
                                       g_free,
 | 
			
		||||
                                       g_object_unref);
 | 
			
		||||
                                       free,
 | 
			
		||||
                                       NULL);
 | 
			
		||||
 | 
			
		||||
  while (TRUE) {
 | 
			
		||||
  state = NULL;
 | 
			
		||||
  while (true) {
 | 
			
		||||
    SpaMonitorItem *item;
 | 
			
		||||
    SpaResult res;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +220,32 @@ pinos_spa_v4l2_monitor_new (PinosCore *core)
 | 
			
		|||
  }
 | 
			
		||||
  spa_monitor_set_event_callback (this->monitor, on_monitor_event, this);
 | 
			
		||||
 | 
			
		||||
  pinos_registry_add_object (&core->registry, &impl->object);
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,26 +17,36 @@
 | 
			
		|||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PINOS_SPA_V4L2_MONITOR_H__
 | 
			
		||||
#define __PINOS_SPA_V4L2_MONITOR_H__
 | 
			
		||||
#ifndef __PINOS_SPA_MONITOR_H__
 | 
			
		||||
#define __PINOS_SPA_MONITOR_H__
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/core.h>
 | 
			
		||||
#include <spa/include/spa/monitor.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosSpaV4l2Monitor PinosSpaV4l2Monitor;
 | 
			
		||||
typedef struct _PinosSpaMonitor PinosSpaMonitor;
 | 
			
		||||
 | 
			
		||||
struct _PinosSpaV4l2Monitor {
 | 
			
		||||
struct _PinosSpaMonitor {
 | 
			
		||||
  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);
 | 
			
		||||
void                       pinos_spa_v4l2_monitor_destroy  (PinosSpaV4l2Monitor *monitor);
 | 
			
		||||
PinosSpaMonitor *      pinos_spa_monitor_load     (PinosCore  *core,
 | 
			
		||||
                                                   const char *lib,
 | 
			
		||||
                                                   const char *factory_name,
 | 
			
		||||
                                                   const char *args);
 | 
			
		||||
void                   pinos_spa_monitor_destroy  (PinosSpaMonitor *monitor);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __PINOS_SPA_V4L2_MONITOR_H__ */
 | 
			
		||||
#endif /* __PINOS_SPA_MONITOR_H__ */
 | 
			
		||||
							
								
								
									
										138
									
								
								pinos/modules/spa/spa-node.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								pinos/modules/spa/spa-node.c
									
										
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								pinos/modules/spa/spa-node.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								pinos/modules/spa/spa-node.h
									
										
									
									
									
										Normal 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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -102,12 +102,12 @@ struct _SpaProxy
 | 
			
		|||
  SpaNodeEventCallback event_cb;
 | 
			
		||||
  void *user_data;
 | 
			
		||||
 | 
			
		||||
  SpaPollFd fds[1];
 | 
			
		||||
  SpaPollItem poll;
 | 
			
		||||
  SpaPollFd ctrl_fds[1];
 | 
			
		||||
  SpaPollItem ctrl_poll;
 | 
			
		||||
  PinosConnection *conn;
 | 
			
		||||
 | 
			
		||||
  SpaPollFd rtfds[1];
 | 
			
		||||
  SpaPollItem rtpoll;
 | 
			
		||||
  SpaPollFd data_fds[1];
 | 
			
		||||
  SpaPollItem data_poll;
 | 
			
		||||
 | 
			
		||||
  unsigned int max_inputs;
 | 
			
		||||
  unsigned int n_inputs;
 | 
			
		||||
| 
						 | 
				
			
			@ -123,17 +123,15 @@ typedef struct
 | 
			
		|||
{
 | 
			
		||||
  PinosClientNode this;
 | 
			
		||||
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosInterface ifaces[1];
 | 
			
		||||
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
 | 
			
		||||
  SpaProxy proxy;
 | 
			
		||||
 | 
			
		||||
  PinosListener transport_changed;
 | 
			
		||||
  PinosListener loop_changed;
 | 
			
		||||
 | 
			
		||||
  int fd;
 | 
			
		||||
  int rtfd;
 | 
			
		||||
  int ctrl_fd;
 | 
			
		||||
  int data_fd;
 | 
			
		||||
} PinosClientNodeImpl;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -862,7 +860,7 @@ spa_proxy_node_port_reuse_buffer (SpaNode         *node,
 | 
			
		|||
  rb.buffer_id = buffer_id;
 | 
			
		||||
  pinos_transport_add_event (pnode->transport, &rb.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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -931,7 +929,7 @@ spa_proxy_node_process_input (SpaNode *node)
 | 
			
		|||
    return SPA_RESULT_ERROR;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,7 +1103,7 @@ proxy_on_fd_events (SpaPollNotifyData *data)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
proxy_on_rtfd_events (SpaPollNotifyData *data)
 | 
			
		||||
proxy_on_data_fd_events (SpaPollNotifyData *data)
 | 
			
		||||
{
 | 
			
		||||
  SpaProxy *this = data->user_data;
 | 
			
		||||
  PinosNode *pnode = this->pnode;
 | 
			
		||||
| 
						 | 
				
			
			@ -1113,7 +1111,7 @@ proxy_on_rtfd_events (SpaPollNotifyData *data)
 | 
			
		|||
  if (data->fds[0].revents & POLLIN) {
 | 
			
		||||
    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) {
 | 
			
		||||
      SpaNodeEvent event;
 | 
			
		||||
| 
						 | 
				
			
			@ -1194,41 +1192,39 @@ proxy_init (SpaProxy         *this,
 | 
			
		|||
 | 
			
		||||
  this->node = proxy_node;
 | 
			
		||||
 | 
			
		||||
  this->fds[0].fd = -1;
 | 
			
		||||
  this->fds[0].events = POLLIN | POLLPRI | POLLERR;
 | 
			
		||||
  this->fds[0].revents = 0;
 | 
			
		||||
  this->poll.id = 0;
 | 
			
		||||
  this->poll.enabled = true;
 | 
			
		||||
  this->poll.fds = this->fds;
 | 
			
		||||
  this->poll.n_fds = 1;
 | 
			
		||||
  this->poll.idle_cb = NULL;
 | 
			
		||||
  this->poll.before_cb = NULL;
 | 
			
		||||
  this->poll.after_cb = proxy_on_fd_events;
 | 
			
		||||
  this->poll.user_data = this;
 | 
			
		||||
  this->ctrl_fds[0].fd = -1;
 | 
			
		||||
  this->ctrl_fds[0].events = POLLIN | POLLPRI | POLLERR;
 | 
			
		||||
  this->ctrl_fds[0].revents = 0;
 | 
			
		||||
  this->ctrl_poll.id = 0;
 | 
			
		||||
  this->ctrl_poll.enabled = true;
 | 
			
		||||
  this->ctrl_poll.fds = this->ctrl_fds;
 | 
			
		||||
  this->ctrl_poll.n_fds = 1;
 | 
			
		||||
  this->ctrl_poll.idle_cb = NULL;
 | 
			
		||||
  this->ctrl_poll.before_cb = NULL;
 | 
			
		||||
  this->ctrl_poll.after_cb = proxy_on_fd_events;
 | 
			
		||||
  this->ctrl_poll.user_data = this;
 | 
			
		||||
 | 
			
		||||
  this->rtfds[0].fd = -1;
 | 
			
		||||
  this->rtfds[0].events = POLLIN | POLLPRI | POLLERR;
 | 
			
		||||
  this->rtfds[0].revents = 0;
 | 
			
		||||
  this->rtpoll.id = 0;
 | 
			
		||||
  this->rtpoll.enabled = true;
 | 
			
		||||
  this->rtpoll.fds = this->rtfds;
 | 
			
		||||
  this->rtpoll.n_fds = 1;
 | 
			
		||||
  this->rtpoll.idle_cb = NULL;
 | 
			
		||||
  this->rtpoll.before_cb = NULL;
 | 
			
		||||
  this->rtpoll.after_cb = proxy_on_rtfd_events;
 | 
			
		||||
  this->rtpoll.user_data = this;
 | 
			
		||||
  this->data_fds[0].fd = -1;
 | 
			
		||||
  this->data_fds[0].events = POLLIN | POLLPRI | POLLERR;
 | 
			
		||||
  this->data_fds[0].revents = 0;
 | 
			
		||||
  this->data_poll.id = 0;
 | 
			
		||||
  this->data_poll.enabled = true;
 | 
			
		||||
  this->data_poll.fds = this->data_fds;
 | 
			
		||||
  this->data_poll.n_fds = 1;
 | 
			
		||||
  this->data_poll.idle_cb = NULL;
 | 
			
		||||
  this->data_poll.before_cb = NULL;
 | 
			
		||||
  this->data_poll.after_cb = proxy_on_data_fd_events;
 | 
			
		||||
  this->data_poll.user_data = this;
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_RETURN_ASYNC (this->seq++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_transport_changed (PinosListener   *listener,
 | 
			
		||||
                      void            *object,
 | 
			
		||||
                      void            *data)
 | 
			
		||||
                      PinosNode       *node)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (listener, PinosClientNodeImpl, transport_changed);
 | 
			
		||||
  PinosClientNode *this = &impl->this;
 | 
			
		||||
  PinosNode *node = object;
 | 
			
		||||
  PinosTransportInfo info;
 | 
			
		||||
  PinosMessageTransportUpdate tu;
 | 
			
		||||
  PinosConnection *conn = impl->proxy.conn;
 | 
			
		||||
| 
						 | 
				
			
			@ -1244,6 +1240,14 @@ on_transport_changed (PinosListener   *listener,
 | 
			
		|||
    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
 | 
			
		||||
proxy_clear (SpaProxy *this)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1257,35 +1261,18 @@ proxy_clear (SpaProxy *this)
 | 
			
		|||
    if (this->out_ports[i].valid)
 | 
			
		||||
      clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->fds[0].fd != -1) {
 | 
			
		||||
    spa_poll_remove_item (this->main_loop, &this->poll);
 | 
			
		||||
    close (this->fds[0].fd);
 | 
			
		||||
  if (this->ctrl_fds[0].fd != -1) {
 | 
			
		||||
    spa_poll_remove_item (this->main_loop, &this->ctrl_poll);
 | 
			
		||||
    close (this->ctrl_fds[0].fd);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->rtfds[0].fd != -1) {
 | 
			
		||||
    spa_poll_remove_item (this->data_loop, &this->rtpoll);
 | 
			
		||||
    close (this->rtfds[0].fd);
 | 
			
		||||
  if (this->data_fds[0].fd != -1) {
 | 
			
		||||
    spa_poll_remove_item (this->data_loop, &this->data_poll);
 | 
			
		||||
    close (this->data_fds[0].fd);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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:
 | 
			
		||||
 * @daemon: a #PinosDaemon
 | 
			
		||||
| 
						 | 
				
			
			@ -1310,16 +1297,12 @@ pinos_client_node_new (PinosCore       *core,
 | 
			
		|||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosClientNodeImpl));
 | 
			
		||||
  impl->core = core;
 | 
			
		||||
  impl->ctrl_fd = -1;
 | 
			
		||||
  impl->data_fd = -1;
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  pinos_log_debug ("client-node %p: new", impl);
 | 
			
		||||
 | 
			
		||||
  impl->ifaces[0].type = impl->core->registry.uri.node;
 | 
			
		||||
  impl->ifaces[0].iface = this;
 | 
			
		||||
 | 
			
		||||
  pinos_object_init (&this->object,
 | 
			
		||||
                     client_node_destroy,
 | 
			
		||||
                     1,
 | 
			
		||||
                     impl->ifaces);
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  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->transport_changed.notify = on_transport_changed;
 | 
			
		||||
  pinos_signal_add (&this->node->transport_changed, &impl->transport_changed);
 | 
			
		||||
  pinos_signal_add (&this->node->transport_changed,
 | 
			
		||||
                    &impl->transport_changed,
 | 
			
		||||
                    on_transport_changed);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&this->node->loop_changed,
 | 
			
		||||
                    &impl->loop_changed,
 | 
			
		||||
                    on_loop_changed);
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
 * @error: a #GError
 | 
			
		||||
 * @fd: a result socket
 | 
			
		||||
 *
 | 
			
		||||
 * 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
 | 
			
		||||
pinos_client_node_get_socket_pair (PinosClientNode  *this,
 | 
			
		||||
                                   GError          **error)
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_client_node_get_ctrl_socket (PinosClientNode  *this,
 | 
			
		||||
                                   int              *fd)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = (PinosClientNodeImpl *) this;
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (this, -1);
 | 
			
		||||
 | 
			
		||||
  if (impl->fd == -1) {
 | 
			
		||||
  if (impl->ctrl_fd == -1) {
 | 
			
		||||
    int fd[2];
 | 
			
		||||
 | 
			
		||||
    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.conn = pinos_connection_new (impl->proxy.fds[0].fd);
 | 
			
		||||
    spa_poll_add_item (impl->proxy.main_loop, &impl->proxy.poll);
 | 
			
		||||
    impl->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;
 | 
			
		||||
    impl->proxy.ctrl_fds[0].fd = fd[0];
 | 
			
		||||
    impl->proxy.conn = pinos_connection_new (impl->proxy.ctrl_fds[0].fd);
 | 
			
		||||
    spa_poll_add_item (impl->proxy.main_loop, &impl->proxy.ctrl_poll);
 | 
			
		||||
    impl->ctrl_fd = fd[1];
 | 
			
		||||
  }
 | 
			
		||||
  *fd = impl->ctrl_fd;
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_client_node_get_rtsocket_pair:
 | 
			
		||||
 * pinos_client_node_get_data_socket:
 | 
			
		||||
 * @node: a #PinosClientNode
 | 
			
		||||
 * @error: a #GError
 | 
			
		||||
 *
 | 
			
		||||
 * Create or return a previously create socket pair for @node. The
 | 
			
		||||
 * 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
 | 
			
		||||
pinos_client_node_get_rtsocket_pair (PinosClientNode  *this,
 | 
			
		||||
                                     GError          **error)
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_client_node_get_data_socket (PinosClientNode  *this,
 | 
			
		||||
                                   int              *fd)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = (PinosClientNodeImpl *) this;
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this);
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (this, -1);
 | 
			
		||||
 | 
			
		||||
  if (impl->fd == -1) {
 | 
			
		||||
  if (impl->data_fd == -1) {
 | 
			
		||||
    int fd[2];
 | 
			
		||||
 | 
			
		||||
    if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0)
 | 
			
		||||
      goto no_sockets;
 | 
			
		||||
      return SPA_RESULT_ERRNO;
 | 
			
		||||
 | 
			
		||||
    impl->proxy.rtfds[0].fd = fd[0];
 | 
			
		||||
    spa_poll_add_item (impl->proxy.data_loop, &impl->proxy.rtpoll);
 | 
			
		||||
    impl->rtfd = 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;
 | 
			
		||||
    impl->proxy.data_fds[0].fd = fd[0];
 | 
			
		||||
    spa_poll_add_item (impl->proxy.data_loop, &impl->proxy.data_poll);
 | 
			
		||||
    impl->data_fd = fd[1];
 | 
			
		||||
  }
 | 
			
		||||
  *fd = impl->data_fd;
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,14 +20,11 @@
 | 
			
		|||
#ifndef __PINOS_CLIENT_NODE_H__
 | 
			
		||||
#define __PINOS_CLIENT_NODE_H__
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/node.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define PINOS_CLIENT_NODE_URI                            "http://pinos.org/ns/client-node"
 | 
			
		||||
#define PINOS_CLIENT_NODE_PREFIX                         PINOS_CLIENT_NODE_URI "#"
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosClientNode PinosClientNode;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -39,20 +36,21 @@ typedef struct _PinosClientNode PinosClientNode;
 | 
			
		|||
struct _PinosClientNode {
 | 
			
		||||
  PinosNode *node;
 | 
			
		||||
 | 
			
		||||
  int  (*get_ctrl_socket)      (PinosClientNode  *node,
 | 
			
		||||
                                GError          **error);
 | 
			
		||||
  int  (*get_data_socket)      (PinosClientNode  *node,
 | 
			
		||||
                                GError          **error);
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener   *listener,
 | 
			
		||||
                                 PinosClientNode *node));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PinosObject *      pinos_client_node_new                  (PinosCore       *core,
 | 
			
		||||
PinosClientNode *  pinos_client_node_new              (PinosCore       *core,
 | 
			
		||||
                                                       PinosClient     *client,
 | 
			
		||||
                                                       const gchar     *name,
 | 
			
		||||
                                                       PinosProperties *properties);
 | 
			
		||||
void               pinos_client_node_destroy          (PinosClientNode *node);
 | 
			
		||||
 | 
			
		||||
#define pinos_client_node_get_ctrl_socket(n)   (n)->get_ctrl_socket(n,__VA_ARGS__)
 | 
			
		||||
#define pinos_client_node_get_data_socket(n)   (n)->get_data_socket(n,__VA_ARGS__)
 | 
			
		||||
SpaResult          pinos_client_node_get_ctrl_socket  (PinosClientNode *node, int *fd);
 | 
			
		||||
SpaResult          pinos_client_node_get_data_socket  (PinosClientNode *node, int *fd);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __PINOS_CLIENT_NODE_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,10 +26,7 @@
 | 
			
		|||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosClient client;
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosInterface ifaces[1];
 | 
			
		||||
  PinosDaemon *daemon;
 | 
			
		||||
  PinosClient this;
 | 
			
		||||
 | 
			
		||||
  guint id;
 | 
			
		||||
  PinosClient1 *iface;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,10 +42,18 @@ client_name_appeared_handler (GDBusConnection *connection,
 | 
			
		|||
                              gpointer         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_signal_emit (&client->appeared, client, NULL);
 | 
			
		||||
  pinos_log_debug ("client %p: appeared %s %s", this, name, name_owner);
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			@ -57,24 +62,24 @@ client_name_vanished_handler (GDBusConnection *connection,
 | 
			
		|||
                              gpointer         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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_watch_name (PinosClient *client)
 | 
			
		||||
client_watch_name (PinosClient *this)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client);
 | 
			
		||||
  GDBusConnection *connection = NULL;
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (this, PinosClientImpl, this);
 | 
			
		||||
 | 
			
		||||
//  g_object_get (impl->daemon, "connection", &connection, NULL);
 | 
			
		||||
 | 
			
		||||
  impl->id = g_bus_watch_name_on_connection (connection,
 | 
			
		||||
                                             client->sender,
 | 
			
		||||
  impl->id = g_bus_watch_name_on_connection (this->core->connection,
 | 
			
		||||
                                             this->sender,
 | 
			
		||||
                                             G_BUS_NAME_WATCHER_FLAGS_NONE,
 | 
			
		||||
                                             client_name_appeared_handler,
 | 
			
		||||
                                             client_name_vanished_handler,
 | 
			
		||||
| 
						 | 
				
			
			@ -82,65 +87,11 @@ client_watch_name (PinosClient *client)
 | 
			
		|||
                                             (GDestroyNotify) pinos_client_destroy);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_register_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,
 | 
			
		||||
void
 | 
			
		||||
pinos_client_add_object (PinosClient *client,
 | 
			
		||||
                         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 (object);
 | 
			
		||||
| 
						 | 
				
			
			@ -148,11 +99,11 @@ client_add_object (PinosClient *client,
 | 
			
		|||
  impl->objects = g_list_prepend (impl->objects, object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
client_remove_object (PinosClient *client,
 | 
			
		||||
void
 | 
			
		||||
pinos_client_remove_object (PinosClient *client,
 | 
			
		||||
                            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 (object);
 | 
			
		||||
| 
						 | 
				
			
			@ -161,11 +112,11 @@ client_remove_object (PinosClient *client,
 | 
			
		|||
  pinos_object_destroy (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
client_has_object (PinosClient *client,
 | 
			
		||||
bool
 | 
			
		||||
pinos_client_has_object (PinosClient *client,
 | 
			
		||||
                         PinosObject *object)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client);
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
 | 
			
		||||
  GList *found;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (client, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -192,36 +143,26 @@ pinos_client_new (PinosCore       *core,
 | 
			
		|||
                  const gchar     *sender,
 | 
			
		||||
                  PinosProperties *properties)
 | 
			
		||||
{
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
  PinosClient *this;
 | 
			
		||||
  PinosClientImpl *impl;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosClientImpl));
 | 
			
		||||
  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 ();
 | 
			
		||||
 | 
			
		||||
  client_watch_name (client);
 | 
			
		||||
  client_register_object (client);
 | 
			
		||||
  client_watch_name (this);
 | 
			
		||||
 | 
			
		||||
  pinos_registry_add_object (&client->core->registry, &impl->object);
 | 
			
		||||
  spa_list_insert (core->client_list.prev, &this->list);
 | 
			
		||||
 | 
			
		||||
  return client;
 | 
			
		||||
  return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -233,12 +174,25 @@ pinos_client_new (PinosCore       *core,
 | 
			
		|||
void
 | 
			
		||||
pinos_client_destroy (PinosClient * client)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, client);
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (client);
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
 | 
			
		||||
  GList *copy;
 | 
			
		||||
 | 
			
		||||
  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 *
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,9 +20,9 @@
 | 
			
		|||
#ifndef __PINOS_CLIENT_H__
 | 
			
		||||
#define __PINOS_CLIENT_H__
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PINOS_CLIENT_URI                            "http://pinos.org/ns/client"
 | 
			
		||||
#define PINOS_CLIENT_PREFIX                         PINOS_CLIENT_URI "#"
 | 
			
		||||
| 
						 | 
				
			
			@ -39,32 +39,33 @@ typedef struct _PinosClient PinosClient;
 | 
			
		|||
 */
 | 
			
		||||
struct _PinosClient {
 | 
			
		||||
  PinosCore   *core;
 | 
			
		||||
  SpaList      list;
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  char *sender;
 | 
			
		||||
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
 | 
			
		||||
  PinosSignal appeared;
 | 
			
		||||
  PinosSignal vanished;
 | 
			
		||||
 | 
			
		||||
  void   (*add_object)          (PinosClient *client,
 | 
			
		||||
                                 PinosObject *object);
 | 
			
		||||
  void   (*remove_object)       (PinosClient *client,
 | 
			
		||||
                                 PinosObject *object);
 | 
			
		||||
  bool   (*has_object)          (PinosClient *client,
 | 
			
		||||
                                 PinosObject *object);
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosClient *client));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PinosObject *   pinos_client_new                  (PinosCore       *core,
 | 
			
		||||
PinosClient *   pinos_client_new                  (PinosCore       *core,
 | 
			
		||||
                                                   const gchar     *sender,
 | 
			
		||||
                                                   PinosProperties *properties);
 | 
			
		||||
void            pinos_client_destroy              (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__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,46 +18,36 @@
 | 
			
		|||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/pinos.h>
 | 
			
		||||
#include <pinos/client/utils.h>
 | 
			
		||||
#include <pinos/server/module.h>
 | 
			
		||||
 | 
			
		||||
#include "command.h"
 | 
			
		||||
 | 
			
		||||
GQuark
 | 
			
		||||
pinos_command_error_quark (void)
 | 
			
		||||
{
 | 
			
		||||
  static GQuark quark = 0;
 | 
			
		||||
 | 
			
		||||
  if (quark == 0) {
 | 
			
		||||
    quark = g_quark_from_static_string ("pinos_command_error");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return quark;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef gboolean (*PinosCommandFunc)                    (PinosCommand  *command,
 | 
			
		||||
typedef bool (*PinosCommandFunc)                    (PinosCommand  *command,
 | 
			
		||||
                                                         PinosCore     *core,
 | 
			
		||||
                                                         GError       **err);
 | 
			
		||||
                                                         char         **err);
 | 
			
		||||
 | 
			
		||||
static gboolean  execute_command_module_load            (PinosCommand  *command,
 | 
			
		||||
static bool  execute_command_module_load            (PinosCommand  *command,
 | 
			
		||||
                                                         PinosCore     *core,
 | 
			
		||||
                                                         GError       **err);
 | 
			
		||||
                                                         char         **err);
 | 
			
		||||
 | 
			
		||||
typedef PinosCommand * (*PinosCommandParseFunc)         (const gchar   *line,
 | 
			
		||||
                                                         GError       **err);
 | 
			
		||||
                                                         char         **err);
 | 
			
		||||
 | 
			
		||||
static PinosCommand *  parse_command_module_load        (const gchar  *line,
 | 
			
		||||
                                                         GError      **err);
 | 
			
		||||
                                                         char         **err);
 | 
			
		||||
 | 
			
		||||
struct _PinosCommand
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosCommand this;
 | 
			
		||||
 | 
			
		||||
  PinosCommandFunc func;
 | 
			
		||||
  gchar **args;
 | 
			
		||||
  gint    n_args;
 | 
			
		||||
};
 | 
			
		||||
  char **args;
 | 
			
		||||
  int    n_args;
 | 
			
		||||
} PinosCommandImpl;
 | 
			
		||||
 | 
			
		||||
typedef struct _CommandParse
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -72,84 +62,40 @@ static const CommandParse parsers[] = {
 | 
			
		|||
 | 
			
		||||
static const gchar whitespace[] = " \t";
 | 
			
		||||
 | 
			
		||||
static gchar **
 | 
			
		||||
tokenize (const gchar * line, gint max_tokens, gint * n_tokens)
 | 
			
		||||
{
 | 
			
		||||
  gchar **res;
 | 
			
		||||
  GSList *tokens, *walk;
 | 
			
		||||
  const gchar *s;
 | 
			
		||||
  gint num;
 | 
			
		||||
 | 
			
		||||
  s = line + strspn (line, whitespace);
 | 
			
		||||
  num = 0;
 | 
			
		||||
  tokens = NULL;
 | 
			
		||||
 | 
			
		||||
  while (*s != '\0' && num + 1 < max_tokens) {
 | 
			
		||||
    gsize len;
 | 
			
		||||
    gchar *token;
 | 
			
		||||
 | 
			
		||||
    len = strcspn (s, whitespace);
 | 
			
		||||
    token = g_strndup (s, len);
 | 
			
		||||
    tokens = g_slist_prepend (tokens, token);
 | 
			
		||||
    num++;
 | 
			
		||||
 | 
			
		||||
    s += len;
 | 
			
		||||
    s += strspn (s, whitespace);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (*s != '\0') {
 | 
			
		||||
    tokens = g_slist_prepend (tokens, g_strdup (s));
 | 
			
		||||
    num++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  res = g_new (gchar *, num + 1);
 | 
			
		||||
  res[num] = NULL;
 | 
			
		||||
  for (walk = tokens; walk != NULL; walk = walk->next) {
 | 
			
		||||
    res[--num] = walk->data;
 | 
			
		||||
  }
 | 
			
		||||
  g_slist_free (tokens);
 | 
			
		||||
 | 
			
		||||
  *n_tokens = num;
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PinosCommand *
 | 
			
		||||
parse_command_module_load (const gchar * line, GError ** err)
 | 
			
		||||
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;
 | 
			
		||||
  command->args = tokenize (line, 3, &command->n_args);
 | 
			
		||||
  impl->func = execute_command_module_load;
 | 
			
		||||
  impl->args = pinos_split_strv (line, whitespace, 3, &impl->n_args);
 | 
			
		||||
 | 
			
		||||
  if (command->args[1] == NULL)
 | 
			
		||||
  if (impl->args[1] == NULL)
 | 
			
		||||
    goto no_module;
 | 
			
		||||
 | 
			
		||||
  return command;
 | 
			
		||||
  impl->this.name = impl->args[0];
 | 
			
		||||
 | 
			
		||||
  return &impl->this;
 | 
			
		||||
 | 
			
		||||
no_module:
 | 
			
		||||
  g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_PARSE,
 | 
			
		||||
      "%s requires a module name", command->args[0]);
 | 
			
		||||
 | 
			
		||||
  g_strfreev (command->args);
 | 
			
		||||
 | 
			
		||||
  asprintf (err, "%s requires a module name", impl->args[0]);
 | 
			
		||||
  pinos_free_strv (impl->args);
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
static bool
 | 
			
		||||
execute_command_module_load (PinosCommand  *command,
 | 
			
		||||
                             PinosCore     *core,
 | 
			
		||||
                             GError       **err)
 | 
			
		||||
                             char         **err)
 | 
			
		||||
{
 | 
			
		||||
  gchar *module;
 | 
			
		||||
  gchar *args;
 | 
			
		||||
  PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
 | 
			
		||||
 | 
			
		||||
  module = command->args[1];
 | 
			
		||||
  args = command->args[2];
 | 
			
		||||
 | 
			
		||||
  return pinos_module_load (core, module, args, err) != NULL;
 | 
			
		||||
  return pinos_module_load (core,
 | 
			
		||||
                            impl->args[1],
 | 
			
		||||
                            impl->args[2],
 | 
			
		||||
                            err) != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -161,57 +107,47 @@ execute_command_module_load (PinosCommand  *command,
 | 
			
		|||
void
 | 
			
		||||
pinos_command_free (PinosCommand * command)
 | 
			
		||||
{
 | 
			
		||||
  g_return_if_fail (command != NULL);
 | 
			
		||||
  PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
 | 
			
		||||
 | 
			
		||||
  g_strfreev (command->args);
 | 
			
		||||
 | 
			
		||||
  g_free (command);
 | 
			
		||||
  spa_list_remove (&command->link);
 | 
			
		||||
  pinos_free_strv (impl->args);
 | 
			
		||||
  free (impl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_command_parse:
 | 
			
		||||
 * @command: (out): Return location for a #PinosCommand
 | 
			
		||||
 * @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().
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %TRUE on success, %FALSE otherwise.
 | 
			
		||||
 * Returns: The command or %NULL when @err is set.
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
pinos_command_parse (PinosCommand ** command,
 | 
			
		||||
                     gchar         * line,
 | 
			
		||||
                     GError       ** err)
 | 
			
		||||
PinosCommand *
 | 
			
		||||
pinos_command_parse (const char     *line,
 | 
			
		||||
                     char         **err)
 | 
			
		||||
{
 | 
			
		||||
  PinosCommand *command = NULL;
 | 
			
		||||
  const CommandParse *parse;
 | 
			
		||||
  gchar *name;
 | 
			
		||||
  gsize len;
 | 
			
		||||
  gboolean ret = FALSE;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (command != NULL && *command == NULL, FALSE);
 | 
			
		||||
  g_return_val_if_fail (line != NULL && *line != '\0', FALSE);
 | 
			
		||||
 | 
			
		||||
  len = strcspn (line, whitespace);
 | 
			
		||||
 | 
			
		||||
  name = g_strndup (line, len);
 | 
			
		||||
  name = strndup (line, len);
 | 
			
		||||
 | 
			
		||||
  for (parse = parsers; parse->name != NULL; parse++) {
 | 
			
		||||
    if (g_strcmp0 (name, parse->name) == 0) {
 | 
			
		||||
      *command = parse->func (line, err);
 | 
			
		||||
      if (*command != NULL)
 | 
			
		||||
        ret = TRUE;
 | 
			
		||||
    if (strcmp (name, parse->name) == 0) {
 | 
			
		||||
      command = parse->func (line, err);
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  g_set_error (err, PINOS_COMMAND_ERROR, PINOS_COMMAND_ERROR_NO_SUCH_COMMAND,
 | 
			
		||||
      "Command \"%s\" does not exist", name);
 | 
			
		||||
 | 
			
		||||
  asprintf (err, "Command \"%s\" does not exist", name);
 | 
			
		||||
out:
 | 
			
		||||
  g_free (name);
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
  free (name);
 | 
			
		||||
  return command;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -222,17 +158,16 @@ out:
 | 
			
		|||
 *
 | 
			
		||||
 * 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,
 | 
			
		||||
                   PinosCore     *core,
 | 
			
		||||
                   GError       **err)
 | 
			
		||||
                   char         **err)
 | 
			
		||||
{
 | 
			
		||||
  g_return_val_if_fail (command != NULL, FALSE);
 | 
			
		||||
  g_return_val_if_fail (core, FALSE);
 | 
			
		||||
  PinosCommandImpl *impl = SPA_CONTAINER_OF (command, PinosCommandImpl, this);
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
 */
 | 
			
		||||
const gchar *
 | 
			
		||||
const char *
 | 
			
		||||
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];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,49 +21,30 @@
 | 
			
		|||
#ifndef __PINOS_COMMAND_H__
 | 
			
		||||
#define __PINOS_COMMAND_H__
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/daemon.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosCommand PinosCommand;
 | 
			
		||||
 | 
			
		||||
GQuark pinos_command_error_quark (void);
 | 
			
		||||
/**
 | 
			
		||||
 * PINOS_COMMAND_ERROR:
 | 
			
		||||
 *
 | 
			
		||||
 * Pinos command error.
 | 
			
		||||
 */
 | 
			
		||||
#define PINOS_COMMAND_ERROR (pinos_command_error_quark ())
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PinosCommandError:
 | 
			
		||||
 * @PINOS_COMMAND_ERROR_GENERIC: Generic command error.
 | 
			
		||||
 * @PINOS_COMMAND_ERROR_NO_SUCH_COMMAND: No such command.
 | 
			
		||||
 * @PINOS_COMMAND_ERROR_PARSE: Failed to parse command.
 | 
			
		||||
 * @PINOS_COMMAND_ERROR_FAILED: Command failed to execute.
 | 
			
		||||
 *
 | 
			
		||||
 * Error codes for Pinos command.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  PINOS_COMMAND_ERROR_GENERIC,
 | 
			
		||||
  PINOS_COMMAND_ERROR_NO_SUCH_COMMAND,
 | 
			
		||||
  PINOS_COMMAND_ERROR_PARSE,
 | 
			
		||||
  PINOS_COMMAND_ERROR_FAILED,
 | 
			
		||||
} PinosCommandError;
 | 
			
		||||
struct _PinosCommand {
 | 
			
		||||
  SpaList link;
 | 
			
		||||
 | 
			
		||||
  const char *name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void               pinos_command_free                 (PinosCommand *command);
 | 
			
		||||
 | 
			
		||||
gboolean           pinos_command_parse                (PinosCommand **command,
 | 
			
		||||
                                                       gchar         *line,
 | 
			
		||||
                                                       GError       **err);
 | 
			
		||||
gboolean           pinos_command_run                  (PinosCommand  *command,
 | 
			
		||||
PinosCommand *     pinos_command_parse                (const char    *line,
 | 
			
		||||
                                                       char         **err);
 | 
			
		||||
bool               pinos_command_run                  (PinosCommand  *command,
 | 
			
		||||
                                                       PinosCore     *core,
 | 
			
		||||
                                                       GError       **err);
 | 
			
		||||
const gchar *      pinos_command_get_name             (PinosCommand  *command);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
                                                       char         **err);
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __PINOS_COMMAND_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,46 +21,93 @@
 | 
			
		|||
#include <pinos/server/data-loop.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosCore object;
 | 
			
		||||
  PinosCore  this;
 | 
			
		||||
 | 
			
		||||
  PinosDataLoop *data_loop;
 | 
			
		||||
  GDBusObjectManagerServer *server_manager;
 | 
			
		||||
 | 
			
		||||
  SpaSupport support[4];
 | 
			
		||||
 | 
			
		||||
} PinosCoreImpl;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
core_destroy (PinosObject *object)
 | 
			
		||||
{
 | 
			
		||||
  free (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosCore *
 | 
			
		||||
pinos_core_new (PinosMainLoop *main_loop)
 | 
			
		||||
{
 | 
			
		||||
  PinosCoreImpl *impl;
 | 
			
		||||
  PinosCore *this;
 | 
			
		||||
 | 
			
		||||
  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,
 | 
			
		||||
                     impl->object.registry.uri.core,
 | 
			
		||||
                     impl,
 | 
			
		||||
                     core_destroy);
 | 
			
		||||
 | 
			
		||||
  impl->data_loop = pinos_data_loop_new ();
 | 
			
		||||
  impl->object.main_loop = main_loop;
 | 
			
		||||
  this->data_loop = pinos_data_loop_new ();
 | 
			
		||||
  this->main_loop = main_loop;
 | 
			
		||||
 | 
			
		||||
  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].data = pinos_log_get ();
 | 
			
		||||
  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].data = &impl->object.main_loop->poll;
 | 
			
		||||
  impl->object.support = impl->support;
 | 
			
		||||
  impl->object.n_support = 4;
 | 
			
		||||
  impl->support[3].data = this->main_loop->poll;
 | 
			
		||||
  this->support = impl->support;
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,14 +24,30 @@
 | 
			
		|||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PINOS_CORE_URI                            "http://pinos.org/ns/core"
 | 
			
		||||
#define PINOS_CORE_PREFIX                         PINOS_CORE_URI "#"
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosCore PinosCore;
 | 
			
		||||
typedef struct _PinosGlobal PinosGlobal;
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/log.h>
 | 
			
		||||
#include <pinos/server/main-loop.h>
 | 
			
		||||
#include <pinos/server/data-loop.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:
 | 
			
		||||
| 
						 | 
				
			
			@ -39,17 +55,61 @@ typedef struct _PinosCore PinosCore;
 | 
			
		|||
 * Pinos core object class.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosCore {
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
 | 
			
		||||
  PinosRegistry registry;
 | 
			
		||||
 | 
			
		||||
  GDBusConnection *connection;
 | 
			
		||||
 | 
			
		||||
  SpaList global_list;
 | 
			
		||||
  SpaList client_list;
 | 
			
		||||
  SpaList node_list;
 | 
			
		||||
  SpaList link_list;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  PinosMainLoop *main_loop;
 | 
			
		||||
  PinosDataLoop *data_loop;
 | 
			
		||||
 | 
			
		||||
  SpaSupport *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);
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include <gio/gunixfdlist.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -40,22 +41,20 @@
 | 
			
		|||
#include "pinos/dbus/org-pinos.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosDaemon daemon;
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosDaemon this;
 | 
			
		||||
 | 
			
		||||
  GDBusObjectManagerServer *server_manager;
 | 
			
		||||
 | 
			
		||||
  PinosDaemon1 *iface;
 | 
			
		||||
  guint id;
 | 
			
		||||
  GDBusConnection *connection;
 | 
			
		||||
  GDBusObjectManagerServer *server_manager;
 | 
			
		||||
 | 
			
		||||
  gchar *object_path;
 | 
			
		||||
 | 
			
		||||
  PinosDataLoop *data_loop;
 | 
			
		||||
 | 
			
		||||
  PinosListener object_added;
 | 
			
		||||
  PinosListener object_removed;
 | 
			
		||||
  PinosListener global_added;
 | 
			
		||||
  PinosListener global_removed;
 | 
			
		||||
  PinosListener port_added;
 | 
			
		||||
  PinosListener port_removed;
 | 
			
		||||
  PinosListener port_unlinked;
 | 
			
		||||
  PinosListener notify_state;
 | 
			
		||||
  PinosListener node_state_changed;
 | 
			
		||||
  PinosListener link_state_changed;
 | 
			
		||||
 | 
			
		||||
  GHashTable *clients;
 | 
			
		||||
  GHashTable *node_factories;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,60 +62,21 @@ typedef struct {
 | 
			
		|||
 | 
			
		||||
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 *
 | 
			
		||||
sender_get_client (PinosDaemon *daemon,
 | 
			
		||||
                   const gchar *sender,
 | 
			
		||||
                   gboolean create)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
 | 
			
		||||
  client = g_hash_table_lookup (impl->clients, sender);
 | 
			
		||||
  if (client == NULL && create) {
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
handle_create_node (PinosDaemon1           *interface,
 | 
			
		||||
                    GDBusMethodInvocation  *invocation,
 | 
			
		||||
| 
						 | 
				
			
			@ -126,6 +86,7 @@ handle_create_node (PinosDaemon1           *interface,
 | 
			
		|||
                    gpointer                user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = user_data;
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
  PinosNodeFactory *factory;
 | 
			
		||||
  PinosNode *node;
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +94,7 @@ handle_create_node (PinosDaemon1           *interface,
 | 
			
		|||
  PinosProperties *props;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -154,17 +115,10 @@ handle_create_node (PinosDaemon1           *interface,
 | 
			
		|||
 | 
			
		||||
  //pinos_client_add_object (client, &node->object);
 | 
			
		||||
 | 
			
		||||
  //g_signal_connect (node,
 | 
			
		||||
   //                 "remove",
 | 
			
		||||
    //                (GCallback) handle_remove_node,
 | 
			
		||||
     //               client);
 | 
			
		||||
 | 
			
		||||
  object_path = pinos_node_get_object_path (node);
 | 
			
		||||
  object_path = node->global->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_variant_new ("(o)", object_path));
 | 
			
		||||
  g_object_unref (node);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
  /* ERRORS */
 | 
			
		||||
| 
						 | 
				
			
			@ -187,39 +141,34 @@ no_node:
 | 
			
		|||
 | 
			
		||||
static void
 | 
			
		||||
on_link_port_unlinked (PinosListener *listener,
 | 
			
		||||
                       void          *object,
 | 
			
		||||
                       void          *data)
 | 
			
		||||
                       PinosLink     *link,
 | 
			
		||||
                       PinosPort     *port)
 | 
			
		||||
{
 | 
			
		||||
  PinosLink *link = object;
 | 
			
		||||
  PinosPort *port = data;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, port_unlinked);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("daemon %p: link %p: port %p unlinked", impl, link, port);
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
on_link_notify_state (PinosListener *listener,
 | 
			
		||||
                      void          *object,
 | 
			
		||||
                      void          *data)
 | 
			
		||||
on_link_state_changed (PinosListener *listener,
 | 
			
		||||
                       PinosLink     *link)
 | 
			
		||||
{
 | 
			
		||||
  PinosLink *link = object;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, notify_state);
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, link_state_changed);
 | 
			
		||||
  PinosLinkState state;
 | 
			
		||||
 | 
			
		||||
  state = pinos_link_get_state (link, &error);
 | 
			
		||||
  state = link->state;
 | 
			
		||||
  switch (state) {
 | 
			
		||||
    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)
 | 
			
		||||
        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)
 | 
			
		||||
        pinos_node_report_error (link->output->node, g_error_copy (error));
 | 
			
		||||
        pinos_node_report_error (link->output->node, g_error_copy (link->error));
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -251,10 +200,10 @@ on_link_notify_state (PinosListener *listener,
 | 
			
		|||
static void
 | 
			
		||||
try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = (PinosDaemonImpl *) this;
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
  //PinosDaemonImpl *impl = SPA_CONTAINER_OF (this, PinosDaemonImpl, this);
 | 
			
		||||
  //PinosClient *client;
 | 
			
		||||
  PinosProperties *props;
 | 
			
		||||
  const gchar *path;
 | 
			
		||||
  const char *path;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  PinosLink *link;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -284,19 +233,14 @@ try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this)
 | 
			
		|||
    if (link == NULL)
 | 
			
		||||
      goto error;
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    client = pinos_node_get_client (node);
 | 
			
		||||
    if (client)
 | 
			
		||||
      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);
 | 
			
		||||
 | 
			
		||||
    g_object_unref (link);
 | 
			
		||||
  }
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -308,62 +252,64 @@ error:
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
on_port_removed (PinosNode *node, PinosPort *port, PinosDaemon *this)
 | 
			
		||||
on_port_removed (PinosListener *listener,
 | 
			
		||||
                 PinosNode     *node,
 | 
			
		||||
                 PinosPort     *port)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_node_created (PinosNode       *node,
 | 
			
		||||
                 PinosDaemon    *this)
 | 
			
		||||
                 PinosDaemonImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  GList *ports, *walk;
 | 
			
		||||
 | 
			
		||||
  ports = pinos_node_get_ports (node, PINOS_DIRECTION_INPUT);
 | 
			
		||||
  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);
 | 
			
		||||
  for (walk = ports; walk; walk = g_list_next (walk))
 | 
			
		||||
    on_port_added (node, walk->data, this);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (node, "port-added", (GCallback) on_port_added, this);
 | 
			
		||||
  g_signal_connect (node, "port-removed", (GCallback) on_port_removed, this);
 | 
			
		||||
    on_port_added (&impl->port_added, node, walk->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_node_state_change (PinosNode      *node,
 | 
			
		||||
on_node_state_changed (PinosListener  *listener,
 | 
			
		||||
                       PinosNode      *node,
 | 
			
		||||
                       PinosNodeState  old,
 | 
			
		||||
                      PinosNodeState  state,
 | 
			
		||||
                      PinosDaemon    *this)
 | 
			
		||||
                       PinosNodeState  state)
 | 
			
		||||
{
 | 
			
		||||
  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 (state));
 | 
			
		||||
 | 
			
		||||
  if (old == PINOS_NODE_STATE_CREATING && state == PINOS_NODE_STATE_SUSPENDED)
 | 
			
		||||
    on_node_created (node, this);
 | 
			
		||||
    on_node_created (node, impl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
  g_object_set (node, "data-loop", impl->data_loop, NULL);
 | 
			
		||||
 | 
			
		||||
  g_signal_connect (node, "state-change", (GCallback) on_node_state_change, impl);
 | 
			
		||||
  pinos_node_set_data_loop (node, daemon->core->data_loop);
 | 
			
		||||
 | 
			
		||||
  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)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = user_data;
 | 
			
		||||
  PinosDaemon *this = &impl->daemon;
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
  PinosClientNode *node;
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
  const gchar *sender, *object_path;
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
  const char *sender, *object_path;
 | 
			
		||||
  PinosProperties *props;
 | 
			
		||||
  GError *error = NULL;
 | 
			
		||||
  GUnixFDList *fdlist;
 | 
			
		||||
  int socket, rtsocket;
 | 
			
		||||
  gint fdidx, rtfdidx;
 | 
			
		||||
  int ctrl_fd, data_fd;
 | 
			
		||||
  int ctrl_idx, data_idx;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  props = pinos_properties_from_variant (arg_properties);
 | 
			
		||||
| 
						 | 
				
			
			@ -402,35 +349,32 @@ handle_create_client_node (PinosDaemon1           *interface,
 | 
			
		|||
                                client,
 | 
			
		||||
                                arg_name,
 | 
			
		||||
                                props);
 | 
			
		||||
  pinos_properties_free (props);
 | 
			
		||||
 | 
			
		||||
  socket = pinos_client_node_get_socket_pair (node, &error);
 | 
			
		||||
  if (socket == -1)
 | 
			
		||||
  if ((res = pinos_client_node_get_ctrl_socket (node, &ctrl_fd)) < 0)
 | 
			
		||||
    goto no_socket;
 | 
			
		||||
 | 
			
		||||
  rtsocket = pinos_client_node_get_rtsocket_pair (node, &error);
 | 
			
		||||
  if (rtsocket == -1)
 | 
			
		||||
  if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0)
 | 
			
		||||
    goto no_socket;
 | 
			
		||||
 | 
			
		||||
  //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);
 | 
			
		||||
 | 
			
		||||
  fdlist = g_unix_fd_list_new ();
 | 
			
		||||
  fdidx = g_unix_fd_list_append (fdlist, socket, &error);
 | 
			
		||||
  rtfdidx = g_unix_fd_list_append (fdlist, rtsocket, &error);
 | 
			
		||||
  ctrl_idx = g_unix_fd_list_append (fdlist, ctrl_fd, &error);
 | 
			
		||||
  data_idx = g_unix_fd_list_append (fdlist, data_fd, &error);
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  return TRUE;
 | 
			
		||||
 | 
			
		||||
no_socket:
 | 
			
		||||
  {
 | 
			
		||||
    pinos_log_debug ("daemon %p: could not create socket %s", impl, error->message);
 | 
			
		||||
    g_object_unref (node);
 | 
			
		||||
    pinos_log_debug ("daemon %p: could not create socket: %s", impl, strerror (errno));
 | 
			
		||||
    pinos_client_node_destroy (node);
 | 
			
		||||
    goto exit_error;
 | 
			
		||||
  }
 | 
			
		||||
exit_error:
 | 
			
		||||
| 
						 | 
				
			
			@ -441,15 +385,14 @@ exit_error:
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static void
 | 
			
		||||
export_server_object (PinosDaemon              *daemon,
 | 
			
		||||
                      GDBusObjectManagerServer *manager)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = (PinosDaemonImpl *) daemon;
 | 
			
		||||
  PinosObjectSkeleton *skel;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (daemon, PinosDaemonImpl, this);
 | 
			
		||||
 | 
			
		||||
  skel = pinos_object_skeleton_new (PINOS_DBUS_OBJECT_SERVER);
 | 
			
		||||
 | 
			
		||||
  pinos_object_skeleton_set_daemon1 (skel, impl->iface);
 | 
			
		||||
 | 
			
		||||
  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)));
 | 
			
		||||
  g_object_unref (skel);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bus_acquired_handler (GDBusConnection *connection,
 | 
			
		||||
| 
						 | 
				
			
			@ -464,12 +408,10 @@ bus_acquired_handler (GDBusConnection *connection,
 | 
			
		|||
                      gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = user_data;
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
  GDBusObjectManagerServer *manager = impl->server_manager;
 | 
			
		||||
 | 
			
		||||
  impl->connection = connection;
 | 
			
		||||
 | 
			
		||||
  export_server_object (&impl->daemon, manager);
 | 
			
		||||
 | 
			
		||||
  this->core->connection = connection;
 | 
			
		||||
  g_dbus_object_manager_server_set_connection (manager, connection);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -486,28 +428,17 @@ name_lost_handler (GDBusConnection *connection,
 | 
			
		|||
                   gpointer         user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosDaemonImpl *impl = user_data;
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
  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_clear_pointer (&impl->object_path, g_free);
 | 
			
		||||
  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;
 | 
			
		||||
  this->core->connection = connection;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpaResult
 | 
			
		||||
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->id == 0, SPA_RESULT_INVALID_ARGUMENTS);
 | 
			
		||||
| 
						 | 
				
			
			@ -529,7 +460,7 @@ daemon_start (PinosDaemon *daemon)
 | 
			
		|||
static SpaResult
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -542,90 +473,59 @@ daemon_stop (PinosDaemon *daemon)
 | 
			
		|||
  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
 | 
			
		||||
on_registry_object_added (PinosListener *listener,
 | 
			
		||||
                          void          *object,
 | 
			
		||||
                          void          *data)
 | 
			
		||||
on_global_added (PinosListener *listener,
 | 
			
		||||
                 PinosCore     *core,
 | 
			
		||||
                 PinosGlobal   *global)
 | 
			
		||||
{
 | 
			
		||||
  PinosObject *obj = data;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, object_added);
 | 
			
		||||
  PinosDaemon *this = &impl->daemon;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, global_added);
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
 | 
			
		||||
  if (obj->type == this->core->registry.uri.node) {
 | 
			
		||||
    PinosNode *node = obj->implementation;
 | 
			
		||||
  if (global->skel) {
 | 
			
		||||
    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);
 | 
			
		||||
  } else if (obj->type == this->core->registry.uri.node_factory) {
 | 
			
		||||
    PinosNodeFactory *factory = obj->implementation;
 | 
			
		||||
    gchar *name;
 | 
			
		||||
  } else if (global->type == this->core->registry.uri.node_factory) {
 | 
			
		||||
    PinosNodeFactory *factory = global->object;
 | 
			
		||||
 | 
			
		||||
    g_object_get (factory, "name", &name, NULL);
 | 
			
		||||
    g_hash_table_insert (impl->node_factories, name, g_object_ref (factory));
 | 
			
		||||
    g_hash_table_insert (impl->node_factories, (void *)factory->name, 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
 | 
			
		||||
on_registry_object_removed (PinosListener *listener,
 | 
			
		||||
                            void          *object,
 | 
			
		||||
                            void          *data)
 | 
			
		||||
on_global_removed (PinosListener *listener,
 | 
			
		||||
                   PinosCore     *core,
 | 
			
		||||
                   PinosGlobal   *global)
 | 
			
		||||
{
 | 
			
		||||
  PinosObject *obj = data;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, object_added);
 | 
			
		||||
  PinosDaemon *this = &impl->daemon;
 | 
			
		||||
  PinosDaemonImpl *impl = SPA_CONTAINER_OF (listener, PinosDaemonImpl, global_removed);
 | 
			
		||||
  PinosDaemon *this = &impl->this;
 | 
			
		||||
 | 
			
		||||
  if (obj->type == this->core->registry.uri.node) {
 | 
			
		||||
    PinosNode *node = obj->implementation;
 | 
			
		||||
  if (global->object_path) {
 | 
			
		||||
    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);
 | 
			
		||||
  } else if (obj->type == this->core->registry.uri.node_factory) {
 | 
			
		||||
    PinosNodeFactory *factory = obj->implementation;
 | 
			
		||||
    gchar *name;
 | 
			
		||||
  } else if (global->type == this->core->registry.uri.node_factory) {
 | 
			
		||||
    PinosNodeFactory *factory = global->object;
 | 
			
		||||
 | 
			
		||||
    g_object_get (factory, "name", &name, NULL);
 | 
			
		||||
    g_hash_table_remove (impl->node_factories, name);
 | 
			
		||||
    g_free (name);
 | 
			
		||||
    g_hash_table_remove (impl->node_factories, factory->name);
 | 
			
		||||
  } else if (global->type == this->core->registry.uri.client) {
 | 
			
		||||
    PinosClient *client = global->object;
 | 
			
		||||
 | 
			
		||||
    g_hash_table_remove (impl->clients, (gpointer) client->sender);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -645,15 +545,14 @@ on_registry_object_removed (PinosListener *listener,
 | 
			
		|||
PinosPort *
 | 
			
		||||
pinos_daemon_find_port (PinosDaemon     *daemon,
 | 
			
		||||
                        PinosPort       *other_port,
 | 
			
		||||
                        const gchar     *name,
 | 
			
		||||
                        const char      *name,
 | 
			
		||||
                        PinosProperties *props,
 | 
			
		||||
                        GPtrArray       *format_filters,
 | 
			
		||||
                        GError         **error)
 | 
			
		||||
{
 | 
			
		||||
  PinosPort *best = NULL;
 | 
			
		||||
  gboolean have_name;
 | 
			
		||||
  void *state = NULL;
 | 
			
		||||
  PinosObject *o;
 | 
			
		||||
  PinosNode *n;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  while ((o = pinos_registry_iterate_nodes (&daemon->core->registry, &state))) {
 | 
			
		||||
    PinosNode *n = o->implementation;
 | 
			
		||||
    if (o->flags & PINOS_OBJECT_FLAG_DESTROYING)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    pinos_log_debug ("node path \"%s\"", pinos_node_get_object_path (n));
 | 
			
		||||
  spa_list_for_each (n, &daemon->core->node_list, list) {
 | 
			
		||||
    pinos_log_debug ("node path \"%s\"", n->global->object_path);
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
 * @core: #PinosCore
 | 
			
		||||
| 
						 | 
				
			
			@ -733,9 +598,10 @@ pinos_daemon_new (PinosCore       *core,
 | 
			
		|||
{
 | 
			
		||||
  PinosDaemonImpl *impl;
 | 
			
		||||
  PinosDaemon *this;
 | 
			
		||||
  PinosObjectSkeleton *skel;
 | 
			
		||||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosDaemonImpl));
 | 
			
		||||
  this = &impl->daemon;
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  pinos_log_debug ("daemon %p: new", impl);
 | 
			
		||||
 | 
			
		||||
  this->core = core;
 | 
			
		||||
| 
						 | 
				
			
			@ -744,27 +610,29 @@ pinos_daemon_new (PinosCore       *core,
 | 
			
		|||
  this->start = daemon_start;
 | 
			
		||||
  this->stop = daemon_stop;
 | 
			
		||||
 | 
			
		||||
  pinos_object_init (&impl->object,
 | 
			
		||||
                     core->registry.uri.daemon,
 | 
			
		||||
                     impl,
 | 
			
		||||
                     daemon_destroy);
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  impl->object_added.notify = on_registry_object_added;
 | 
			
		||||
  pinos_signal_add (&core->registry.object_added, &impl->object_added);
 | 
			
		||||
 | 
			
		||||
  impl->object_removed.notify = on_registry_object_removed;
 | 
			
		||||
  pinos_signal_add (&core->registry.object_removed, &impl->object_removed);
 | 
			
		||||
  pinos_signal_add (&core->global_added, &impl->global_added, on_global_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);
 | 
			
		||||
  pinos_signal_add (&core->port_added, &impl->port_added, on_port_added);
 | 
			
		||||
  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->clients = g_hash_table_new (g_str_hash, g_str_equal);
 | 
			
		||||
  impl->node_factories = g_hash_table_new_full (g_str_hash,
 | 
			
		||||
                                                g_str_equal,
 | 
			
		||||
                                                g_free,
 | 
			
		||||
                                                g_object_unref);
 | 
			
		||||
                                                NULL,
 | 
			
		||||
                                                NULL);
 | 
			
		||||
 | 
			
		||||
  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-client-node", (GCallback) handle_create_client_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, 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_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_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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,25 +39,27 @@ typedef struct _PinosDaemon PinosDaemon;
 | 
			
		|||
 * Pinos daemon object class.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosDaemon {
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  SpaList list;
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosDaemon   *daemon));
 | 
			
		||||
 | 
			
		||||
  SpaResult  (*start)    (PinosDaemon *daemon);
 | 
			
		||||
  SpaResult  (*stop)     (PinosDaemon *daemon);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PinosObject *     pinos_daemon_new               (PinosCore       *core,
 | 
			
		||||
PinosDaemon *     pinos_daemon_new               (PinosCore       *core,
 | 
			
		||||
                                                  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_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       *other_port,
 | 
			
		||||
                                                  const char      *name,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,10 @@ typedef struct {
 | 
			
		|||
  void              *user_data;
 | 
			
		||||
} InvokeItem;
 | 
			
		||||
 | 
			
		||||
struct _PinosDataLoopPrivate
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop this;
 | 
			
		||||
 | 
			
		||||
  SpaRingbuffer buffer;
 | 
			
		||||
  uint8_t       buffer_data[DATAS_SIZE];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,20 +66,7 @@ struct _PinosDataLoopPrivate
 | 
			
		|||
 | 
			
		||||
  bool running;
 | 
			
		||||
  pthread_t thread;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (PinosDataLoop, pinos_data_loop, G_TYPE_OBJECT);
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  PROP_0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  LAST_SIGNAL
 | 
			
		||||
};
 | 
			
		||||
} PinosDataLoopImpl;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
make_realtime (PinosDataLoop *this)
 | 
			
		||||
| 
						 | 
				
			
			@ -126,23 +115,23 @@ make_realtime (PinosDataLoop *this)
 | 
			
		|||
static void *
 | 
			
		||||
loop (void *user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop *this = user_data;
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  PinosDataLoopImpl *impl = user_data;
 | 
			
		||||
  PinosDataLoop *this = &impl->this;
 | 
			
		||||
  SpaPoll *p = &this->poll;
 | 
			
		||||
  unsigned int i, j;
 | 
			
		||||
 | 
			
		||||
  make_realtime (this);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("data-loop %p: enter thread", this);
 | 
			
		||||
  while (priv->running) {
 | 
			
		||||
  while (impl->running) {
 | 
			
		||||
    SpaPollNotifyData ndata;
 | 
			
		||||
    unsigned int n_idle = 0;
 | 
			
		||||
    int r;
 | 
			
		||||
    struct timespec ts;
 | 
			
		||||
 | 
			
		||||
    /* prepare */
 | 
			
		||||
    for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &priv->poll[i];
 | 
			
		||||
    for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &impl->poll[i];
 | 
			
		||||
 | 
			
		||||
      if (p->enabled && p->idle_cb) {
 | 
			
		||||
        ndata.fds = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -157,28 +146,28 @@ loop (void *user_data)
 | 
			
		|||
//      continue;
 | 
			
		||||
 | 
			
		||||
    /* rebuild */
 | 
			
		||||
    if (priv->rebuild_fds) {
 | 
			
		||||
      priv->n_fds = 1;
 | 
			
		||||
      for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
        SpaPollItem *p = &priv->poll[i];
 | 
			
		||||
    if (impl->rebuild_fds) {
 | 
			
		||||
      impl->n_fds = 1;
 | 
			
		||||
      for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
        SpaPollItem *p = &impl->poll[i];
 | 
			
		||||
 | 
			
		||||
        if (!p->enabled)
 | 
			
		||||
          continue;
 | 
			
		||||
 | 
			
		||||
        for (j = 0; j < p->n_fds; j++)
 | 
			
		||||
          priv->fds[priv->n_fds + j] = p->fds[j];
 | 
			
		||||
        priv->idx[i] = priv->n_fds;
 | 
			
		||||
        priv->n_fds += p->n_fds;
 | 
			
		||||
          impl->fds[impl->n_fds + j] = p->fds[j];
 | 
			
		||||
        impl->idx[i] = impl->n_fds;
 | 
			
		||||
        impl->n_fds += p->n_fds;
 | 
			
		||||
      }
 | 
			
		||||
      priv->rebuild_fds = false;
 | 
			
		||||
      impl->rebuild_fds = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* before */
 | 
			
		||||
    for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &priv->poll[i];
 | 
			
		||||
    for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &impl->poll[i];
 | 
			
		||||
 | 
			
		||||
      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.user_data = p->user_data;
 | 
			
		||||
        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 (errno == EINTR)
 | 
			
		||||
        continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -198,17 +187,17 @@ loop (void *user_data)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /* check wakeup */
 | 
			
		||||
    if (priv->fds[0].revents & POLLIN) {
 | 
			
		||||
    if (impl->fds[0].revents & POLLIN) {
 | 
			
		||||
      uint64_t u;
 | 
			
		||||
      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));
 | 
			
		||||
 | 
			
		||||
      while (spa_ringbuffer_get_read_offset (&priv->buffer, &offset) > 0) {
 | 
			
		||||
        InvokeItem *item = SPA_MEMBER (priv->buffer_data, offset, InvokeItem);
 | 
			
		||||
      while (spa_ringbuffer_get_read_offset (&impl->buffer, &offset) > 0) {
 | 
			
		||||
        InvokeItem *item = SPA_MEMBER (impl->buffer_data, offset, InvokeItem);
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -217,11 +206,11 @@ loop (void *user_data)
 | 
			
		|||
//    fprintf (stderr, "%llu\n", SPA_TIMESPEC_TO_TIME (&ts));
 | 
			
		||||
 | 
			
		||||
    /* after */
 | 
			
		||||
    for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &priv->poll[i];
 | 
			
		||||
    for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
      SpaPollItem *p = &impl->poll[i];
 | 
			
		||||
 | 
			
		||||
      if (p->enabled && p->after_cb && (p->n_fds == 0 || priv->fds[priv->idx[i]].revents != 0)) {
 | 
			
		||||
        ndata.fds = &priv->fds[priv->idx[i]];
 | 
			
		||||
      if (p->enabled && p->after_cb && (p->n_fds == 0 || impl->fds[impl->idx[i]].revents != 0)) {
 | 
			
		||||
        ndata.fds = &impl->fds[impl->idx[i]];
 | 
			
		||||
        ndata.n_fds = p->n_fds;
 | 
			
		||||
        ndata.user_data = p->user_data;
 | 
			
		||||
        if (SPA_RESULT_IS_ERROR (p->after_cb (&ndata)))
 | 
			
		||||
| 
						 | 
				
			
			@ -235,40 +224,36 @@ loop (void *user_data)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
wakeup_thread (PinosDataLoop *this)
 | 
			
		||||
wakeup_thread (PinosDataLoopImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  uint64_t u = 1;
 | 
			
		||||
 | 
			
		||||
  if (write (priv->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t))
 | 
			
		||||
    pinos_log_warn ("data-loop %p: failed to write fd: %s", this, strerror (errno));
 | 
			
		||||
  if (write (impl->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t))
 | 
			
		||||
    pinos_log_warn ("data-loop %p: failed to write fd: %s", impl, strerror (errno));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
start_thread (PinosDataLoop *this)
 | 
			
		||||
start_thread (PinosDataLoopImpl *impl)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  if (!priv->running) {
 | 
			
		||||
    priv->running = true;
 | 
			
		||||
    if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) {
 | 
			
		||||
      pinos_log_warn ("data-loop %p: can't create thread: %s", this, strerror (err));
 | 
			
		||||
      priv->running = false;
 | 
			
		||||
  if (!impl->running) {
 | 
			
		||||
    impl->running = true;
 | 
			
		||||
    if ((err = pthread_create (&impl->thread, NULL, loop, impl)) != 0) {
 | 
			
		||||
      pinos_log_warn ("data-loop %p: can't create thread: %s", impl, strerror (err));
 | 
			
		||||
      impl->running = false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
stop_thread (PinosDataLoop *this, bool in_thread)
 | 
			
		||||
stop_thread (PinosDataLoopImpl *impl, bool in_thread)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
 | 
			
		||||
  if (priv->running) {
 | 
			
		||||
    priv->running = false;
 | 
			
		||||
  if (impl->running) {
 | 
			
		||||
    impl->running = false;
 | 
			
		||||
    if (!in_thread) {
 | 
			
		||||
      wakeup_thread (this);
 | 
			
		||||
      pthread_join (priv->thread, NULL);
 | 
			
		||||
      wakeup_thread (impl);
 | 
			
		||||
      pthread_join (impl->thread, NULL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -278,18 +263,18 @@ do_add_item (SpaPoll         *poll,
 | 
			
		|||
             SpaPollItem     *item)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  bool in_thread = pthread_equal (priv->thread, pthread_self());
 | 
			
		||||
  PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
 | 
			
		||||
  bool in_thread = pthread_equal (impl->thread, pthread_self());
 | 
			
		||||
 | 
			
		||||
  item->id = ++priv->counter;
 | 
			
		||||
  priv->poll[priv->n_poll] = *item;
 | 
			
		||||
  priv->n_poll++;
 | 
			
		||||
  item->id = ++impl->counter;
 | 
			
		||||
  impl->poll[impl->n_poll] = *item;
 | 
			
		||||
  impl->n_poll++;
 | 
			
		||||
  if (item->n_fds)
 | 
			
		||||
    priv->rebuild_fds = true;
 | 
			
		||||
    impl->rebuild_fds = true;
 | 
			
		||||
 | 
			
		||||
  if (!in_thread) {
 | 
			
		||||
    wakeup_thread (this);
 | 
			
		||||
    start_thread (this);
 | 
			
		||||
    wakeup_thread (impl);
 | 
			
		||||
    start_thread (impl);
 | 
			
		||||
  }
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -300,19 +285,19 @@ do_update_item (SpaPoll         *poll,
 | 
			
		|||
                SpaPollItem     *item)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  bool in_thread = pthread_equal (priv->thread, pthread_self());
 | 
			
		||||
  PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
 | 
			
		||||
  bool in_thread = pthread_equal (impl->thread, pthread_self());
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
    if (priv->poll[i].id == item->id)
 | 
			
		||||
      priv->poll[i] = *item;
 | 
			
		||||
  for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
    if (impl->poll[i].id == item->id)
 | 
			
		||||
      impl->poll[i] = *item;
 | 
			
		||||
  }
 | 
			
		||||
  if (item->n_fds)
 | 
			
		||||
    priv->rebuild_fds = true;
 | 
			
		||||
    impl->rebuild_fds = true;
 | 
			
		||||
 | 
			
		||||
  if (!in_thread)
 | 
			
		||||
    wakeup_thread (this);
 | 
			
		||||
    wakeup_thread (impl);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -322,22 +307,22 @@ do_remove_item (SpaPoll         *poll,
 | 
			
		|||
                SpaPollItem     *item)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  bool in_thread = pthread_equal (priv->thread, pthread_self());
 | 
			
		||||
  PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
 | 
			
		||||
  bool in_thread = pthread_equal (impl->thread, pthread_self());
 | 
			
		||||
  unsigned int i;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < priv->n_poll; i++) {
 | 
			
		||||
    if (priv->poll[i].id == item->id) {
 | 
			
		||||
      priv->n_poll--;
 | 
			
		||||
      for (; i < priv->n_poll; i++)
 | 
			
		||||
        priv->poll[i] = priv->poll[i+1];
 | 
			
		||||
  for (i = 0; i < impl->n_poll; i++) {
 | 
			
		||||
    if (impl->poll[i].id == item->id) {
 | 
			
		||||
      impl->n_poll--;
 | 
			
		||||
      for (; i < impl->n_poll; i++)
 | 
			
		||||
        impl->poll[i] = impl->poll[i+1];
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (item->n_fds) {
 | 
			
		||||
    priv->rebuild_fds = true;
 | 
			
		||||
    impl->rebuild_fds = true;
 | 
			
		||||
    if (!in_thread)
 | 
			
		||||
      wakeup_thread (this);
 | 
			
		||||
      wakeup_thread (impl);
 | 
			
		||||
  }
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -351,8 +336,8 @@ do_invoke (SpaPoll           *poll,
 | 
			
		|||
           void              *user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll);
 | 
			
		||||
  PinosDataLoopPrivate *priv = this->priv;
 | 
			
		||||
  bool in_thread = pthread_equal (priv->thread, pthread_self());
 | 
			
		||||
  PinosDataLoopImpl *impl = SPA_CONTAINER_OF (this, PinosDataLoopImpl, this);
 | 
			
		||||
  bool in_thread = pthread_equal (impl->thread, pthread_self());
 | 
			
		||||
  SpaRingbufferArea areas[2];
 | 
			
		||||
  InvokeItem *item;
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,12 +345,12 @@ do_invoke (SpaPoll           *poll,
 | 
			
		|||
  if (in_thread) {
 | 
			
		||||
    res = func (poll, false, seq, size, data, user_data);
 | 
			
		||||
  } else {
 | 
			
		||||
    spa_ringbuffer_get_write_areas (&priv->buffer, areas);
 | 
			
		||||
    spa_ringbuffer_get_write_areas (&impl->buffer, areas);
 | 
			
		||||
    if (areas[0].len < sizeof (InvokeItem)) {
 | 
			
		||||
      pinos_log_warn ("queue full");
 | 
			
		||||
      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->func = func;
 | 
			
		||||
    item->user_data = user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -377,14 +362,14 @@ do_invoke (SpaPoll           *poll,
 | 
			
		|||
      if (areas[0].len < sizeof (InvokeItem) + item->item_size)
 | 
			
		||||
        item->item_size = areas[0].len;
 | 
			
		||||
    } 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;
 | 
			
		||||
    }
 | 
			
		||||
    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)
 | 
			
		||||
      res = SPA_RESULT_RETURN_ASYNC (seq);
 | 
			
		||||
| 
						 | 
				
			
			@ -394,72 +379,6 @@ do_invoke (SpaPoll           *poll,
 | 
			
		|||
  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:
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -470,11 +389,45 @@ pinos_data_loop_init (PinosDataLoop * this)
 | 
			
		|||
PinosDataLoop *
 | 
			
		||||
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
 | 
			
		||||
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());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,47 +25,20 @@
 | 
			
		|||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/poll.h>
 | 
			
		||||
#include <spa/include/spa/node-command.h>
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
 *
 | 
			
		||||
 * Pinos rt-loop class.
 | 
			
		||||
 * Pinos rt-loop object.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosDataLoop {
 | 
			
		||||
  GObject object;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
void                pinos_data_loop_destroy          (PinosDataLoop *loop);
 | 
			
		||||
 | 
			
		||||
bool                pinos_data_loop_in_thread        (PinosDataLoop *loop);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,22 +38,13 @@
 | 
			
		|||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosLink link;
 | 
			
		||||
  PinosLink this;
 | 
			
		||||
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosInterface ifaces[1];
 | 
			
		||||
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  PinosDaemon *daemon;
 | 
			
		||||
  PinosLink1 *iface;
 | 
			
		||||
 | 
			
		||||
  gchar *object_path;
 | 
			
		||||
  GPtrArray *format_filter;
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
 | 
			
		||||
  PinosLinkState state;
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  PinosListener input_port_destroy;
 | 
			
		||||
  PinosListener input_async_complete;
 | 
			
		||||
  PinosListener output_port_destroy;
 | 
			
		||||
| 
						 | 
				
			
			@ -65,60 +56,27 @@ typedef struct
 | 
			
		|||
  unsigned int n_buffers;
 | 
			
		||||
} 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
 | 
			
		||||
pinos_link_update_state (PinosLink *link, PinosLinkState state)
 | 
			
		||||
{
 | 
			
		||||
  PinosLinkImpl *impl = (PinosLinkImpl *) link;
 | 
			
		||||
 | 
			
		||||
  if (state != impl->state) {
 | 
			
		||||
    g_clear_error (&impl->error);
 | 
			
		||||
  if (state != link->state) {
 | 
			
		||||
    g_clear_error (&link->error);
 | 
			
		||||
    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));
 | 
			
		||||
    impl->state = state;
 | 
			
		||||
    pinos_signal_emit (&link->notify_state, link, NULL);
 | 
			
		||||
    link->state = state;
 | 
			
		||||
    pinos_signal_emit (&link->core->link_state_changed, link);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
pinos_link_report_error (PinosLink *link, GError *error)
 | 
			
		||||
{
 | 
			
		||||
  PinosLinkImpl *impl = (PinosLinkImpl *) link;
 | 
			
		||||
 | 
			
		||||
  g_clear_error (&impl->error);
 | 
			
		||||
  impl->error = error;
 | 
			
		||||
  impl->state = PINOS_LINK_STATE_ERROR;
 | 
			
		||||
  g_clear_error (&link->error);
 | 
			
		||||
  link->error = error;
 | 
			
		||||
  link->state = PINOS_LINK_STATE_ERROR;
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			@ -152,7 +110,7 @@ again:
 | 
			
		|||
        goto error;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    pinos_log_debug ("Try filter:");
 | 
			
		||||
    pinos_log_debug ("Try filter: %p", filter);
 | 
			
		||||
    spa_debug_format (filter);
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state)
 | 
			
		||||
{
 | 
			
		||||
  PinosLinkImpl *impl = (PinosLinkImpl *) this;
 | 
			
		||||
  PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this);
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
  const SpaPortInfo *iinfo, *oinfo;
 | 
			
		||||
  SpaPortInfoFlags in_flags, out_flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +566,6 @@ check_states (PinosLink *this,
 | 
			
		|||
              SpaResult  res)
 | 
			
		||||
{
 | 
			
		||||
  SpaNodeState in_state, out_state;
 | 
			
		||||
  PinosLinkImpl *impl = (PinosLinkImpl *) this;
 | 
			
		||||
 | 
			
		||||
  if (res != SPA_RESULT_OK) {
 | 
			
		||||
    pinos_log_warn ("link %p: error: %d", this, res);
 | 
			
		||||
| 
						 | 
				
			
			@ -641,34 +598,34 @@ again:
 | 
			
		|||
  return SPA_RESULT_OK;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_input_async_complete_notify (PinosListener *listener,
 | 
			
		||||
                                void          *object,
 | 
			
		||||
                                void          *data)
 | 
			
		||||
                                PinosNode     *node,
 | 
			
		||||
                                uint32_t       seq,
 | 
			
		||||
                                SpaResult      res)
 | 
			
		||||
{
 | 
			
		||||
  PinosNode *node = object;
 | 
			
		||||
  PinosNodeAsyncCompleteData *d = data;
 | 
			
		||||
  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_main_loop_defer_complete (impl->core->main_loop, impl, d->seq, d->res);
 | 
			
		||||
  pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, seq, res);
 | 
			
		||||
  pinos_main_loop_defer_complete (this->core->main_loop, impl, seq, res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_output_async_complete_notify (PinosListener *listener,
 | 
			
		||||
                                 void          *object,
 | 
			
		||||
                                 void          *data)
 | 
			
		||||
                                 PinosNode     *node,
 | 
			
		||||
                                 uint32_t       seq,
 | 
			
		||||
                                 SpaResult      res)
 | 
			
		||||
{
 | 
			
		||||
  PinosNode *node = object;
 | 
			
		||||
  PinosNodeAsyncCompleteData *d = data;
 | 
			
		||||
  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_main_loop_defer_complete (impl->core->main_loop, impl, d->seq, d->res);
 | 
			
		||||
  pinos_log_debug ("link %p: node %p async complete %d %d", impl, node, seq, res);
 | 
			
		||||
  pinos_main_loop_defer_complete (this->core->main_loop, impl, seq, res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
| 
						 | 
				
			
			@ -704,7 +661,7 @@ on_property_notify (GObject    *obj,
 | 
			
		|||
static void
 | 
			
		||||
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)
 | 
			
		||||
    pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED);
 | 
			
		||||
| 
						 | 
				
			
			@ -734,7 +691,7 @@ on_port_destroy (PinosLink *this,
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  res = pinos_port_unlink (port, this);
 | 
			
		||||
  pinos_main_loop_defer (impl->core->main_loop,
 | 
			
		||||
  pinos_main_loop_defer (this->core->main_loop,
 | 
			
		||||
                         port,
 | 
			
		||||
                         res,
 | 
			
		||||
                         (PinosDeferFunc) on_port_unlinked,
 | 
			
		||||
| 
						 | 
				
			
			@ -744,73 +701,34 @@ on_port_destroy (PinosLink *this,
 | 
			
		|||
 | 
			
		||||
static void
 | 
			
		||||
on_input_port_destroy (PinosListener *listener,
 | 
			
		||||
                       void          *object,
 | 
			
		||||
                       void          *data)
 | 
			
		||||
                       PinosPort     *port)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_output_port_destroy (PinosListener *listener,
 | 
			
		||||
                        void          *object,
 | 
			
		||||
                        void          *data)
 | 
			
		||||
                        PinosPort     *port)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
link_destroy (PinosObject * object)
 | 
			
		||||
{
 | 
			
		||||
  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)
 | 
			
		||||
bool
 | 
			
		||||
pinos_link_activate (PinosLink *this)
 | 
			
		||||
{
 | 
			
		||||
  spa_ringbuffer_init (&this->ringbuffer, SPA_N_ELEMENTS (this->queue));
 | 
			
		||||
  check_states (this, NULL, SPA_RESULT_OK);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
pinos_link_deactivate (PinosLink *this)
 | 
			
		||||
bool
 | 
			
		||||
pinos_pinos_link_deactivate (PinosLink *this)
 | 
			
		||||
{
 | 
			
		||||
  spa_ringbuffer_clear (&this->ringbuffer);
 | 
			
		||||
  return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -818,60 +736,61 @@ pinos_link_deactivate (PinosLink *this)
 | 
			
		|||
 | 
			
		||||
PinosLink *
 | 
			
		||||
pinos_link_new (PinosCore       *core,
 | 
			
		||||
                PinosPort       *input,
 | 
			
		||||
                PinosPort       *output,
 | 
			
		||||
                PinosPort       *input,
 | 
			
		||||
                GPtrArray       *format_filter,
 | 
			
		||||
                PinosProperties *properties)
 | 
			
		||||
{
 | 
			
		||||
  PinosLinkImpl *impl;
 | 
			
		||||
  PinosLink *this;
 | 
			
		||||
  PinosObjectSkeleton *skel;
 | 
			
		||||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosLinkImpl));
 | 
			
		||||
  this = &impl->link;
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  pinos_log_debug ("link %p: new", this);
 | 
			
		||||
 | 
			
		||||
  this->core = core;
 | 
			
		||||
  this->properties = properties;
 | 
			
		||||
  this->state = PINOS_LINK_STATE_INIT;
 | 
			
		||||
 | 
			
		||||
  this->input = input;
 | 
			
		||||
  this->output = output;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&this->notify_state);
 | 
			
		||||
  pinos_signal_init (&this->port_unlinked);
 | 
			
		||||
 | 
			
		||||
  this->activate = link_activate;
 | 
			
		||||
  this->deactivate = link_deactivate;
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  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->object.destroy_signal, &impl->input_port_destroy);
 | 
			
		||||
  pinos_signal_add (&this->input->destroy_signal,
 | 
			
		||||
                    &impl->input_port_destroy,
 | 
			
		||||
                    on_input_port_destroy);
 | 
			
		||||
 | 
			
		||||
  impl->output_port_destroy.notify = on_output_port_destroy;
 | 
			
		||||
  pinos_signal_add (&this->output->object.destroy_signal, &impl->output_port_destroy);
 | 
			
		||||
  pinos_signal_add (&this->output->destroy_signal,
 | 
			
		||||
                    &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, &impl->input_async_complete);
 | 
			
		||||
  pinos_signal_add (&this->input->node->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, &impl->output_async_complete);
 | 
			
		||||
 | 
			
		||||
  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_signal_add (&this->output->node->async_complete,
 | 
			
		||||
                    &impl->output_async_complete,
 | 
			
		||||
                    on_output_async_complete_notify);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("link %p: constructed %p:%d -> %p:%d", impl,
 | 
			
		||||
                                                  this->output->node, this->output->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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -883,38 +802,32 @@ pinos_link_new (PinosCore       *core,
 | 
			
		|||
void
 | 
			
		||||
pinos_link_destroy (PinosLink * this)
 | 
			
		||||
{
 | 
			
		||||
  pinos_log_debug ("link %p: destroy", this);
 | 
			
		||||
  pinos_signal_emit (&this->object.destroy_signal, this, NULL);
 | 
			
		||||
  PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("link %p: destroy", impl);
 | 
			
		||||
  pinos_signal_emit (&this->destroy_signal, this);
 | 
			
		||||
 | 
			
		||||
  if (this->input) {
 | 
			
		||||
    pinos_signal_remove (&impl->input_port_destroy);
 | 
			
		||||
    pinos_signal_remove (&impl->input_async_complete);
 | 
			
		||||
    pinos_port_unlink (this->input, this);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->output) {
 | 
			
		||||
    pinos_signal_remove (&impl->output_port_destroy);
 | 
			
		||||
    pinos_signal_remove (&impl->output_async_complete);
 | 
			
		||||
    pinos_port_unlink (this->output, this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_link_get_object_path:
 | 
			
		||||
 * @link: a #PinosLink
 | 
			
		||||
 *
 | 
			
		||||
 * Get the object patch of @link
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: the object path of @source.
 | 
			
		||||
 */
 | 
			
		||||
const gchar *
 | 
			
		||||
pinos_link_get_object_path (PinosLink *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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosLinkState
 | 
			
		||||
pinos_link_get_state (PinosLink  *this,
 | 
			
		||||
                      GError    **error)
 | 
			
		||||
{
 | 
			
		||||
  PinosLinkImpl *impl = (PinosLinkImpl *) this;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (impl, PINOS_LINK_STATE_ERROR);
 | 
			
		||||
 | 
			
		||||
  if (error)
 | 
			
		||||
    *error = impl->error;
 | 
			
		||||
 | 
			
		||||
  return impl->state;
 | 
			
		||||
  spa_list_remove (&this->list);
 | 
			
		||||
 | 
			
		||||
  g_clear_object (&impl->iface);
 | 
			
		||||
 | 
			
		||||
  if (impl->allocated)
 | 
			
		||||
    pinos_memblock_free (&impl->buffer_mem);
 | 
			
		||||
 | 
			
		||||
  free (impl);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,11 +24,11 @@
 | 
			
		|||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosLink PinosLink;
 | 
			
		||||
 | 
			
		||||
#define PINOS_LINK_URI                            "http://pinos.org/ns/link"
 | 
			
		||||
#define PINOS_LINK_PREFIX                         PINOS_LINK_URI "#"
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosLink PinosLink;
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/ringbuffer.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/mem.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -43,33 +43,38 @@ typedef struct _PinosLink PinosLink;
 | 
			
		|||
 * Pinos link interface.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosLink {
 | 
			
		||||
  PinosCore   *core;
 | 
			
		||||
  SpaList      list;
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
 | 
			
		||||
  PinosLinkState state;
 | 
			
		||||
  GError *error;
 | 
			
		||||
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *,
 | 
			
		||||
                                 PinosLink *));
 | 
			
		||||
 | 
			
		||||
  PinosPort    *output;
 | 
			
		||||
  PinosPort    *input;
 | 
			
		||||
 | 
			
		||||
  PinosSignal   port_unlinked;
 | 
			
		||||
  PinosSignal   notify_state;
 | 
			
		||||
 | 
			
		||||
  uint32_t      queue[64];
 | 
			
		||||
  SpaRingbuffer ringbuffer;
 | 
			
		||||
  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       *input,
 | 
			
		||||
                                         GPtrArray       *format_filter,
 | 
			
		||||
                                         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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,8 +62,6 @@ typedef struct
 | 
			
		|||
{
 | 
			
		||||
  PinosMainLoop this;
 | 
			
		||||
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
 | 
			
		||||
  SpaPoll poll;
 | 
			
		||||
 | 
			
		||||
  GMainContext *context;
 | 
			
		||||
| 
						 | 
				
			
			@ -343,6 +341,7 @@ static void
 | 
			
		|||
main_loop_quit (PinosMainLoop *loop)
 | 
			
		||||
{
 | 
			
		||||
  PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
 | 
			
		||||
  pinos_log_debug ("main-loop %p: quit", impl);
 | 
			
		||||
  g_main_loop_quit (impl->loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -350,20 +349,10 @@ static void
 | 
			
		|||
main_loop_run (PinosMainLoop *loop)
 | 
			
		||||
{
 | 
			
		||||
  PinosMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosMainLoopImpl, this);
 | 
			
		||||
  pinos_log_debug ("main-loop %p: run", impl);
 | 
			
		||||
  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:
 | 
			
		||||
 * @context: a #GMainContext or %NULL to use the default context
 | 
			
		||||
| 
						 | 
				
			
			@ -418,3 +407,18 @@ pinos_main_loop_new (GMainContext *context)
 | 
			
		|||
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,10 +22,10 @@
 | 
			
		|||
#include "config.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <gmodule.h>
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
#include "pinos/client/pinos.h"
 | 
			
		||||
#include "pinos/client/utils.h"
 | 
			
		||||
#include "pinos/server/module.h"
 | 
			
		||||
 | 
			
		||||
#define PINOS_SYMBOL_MODULE_INIT "pinos__module_init"
 | 
			
		||||
| 
						 | 
				
			
			@ -34,38 +34,11 @@ typedef struct
 | 
			
		|||
{
 | 
			
		||||
  PinosModule this;
 | 
			
		||||
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosInterface ifaces[1];
 | 
			
		||||
 | 
			
		||||
  GModule *module;
 | 
			
		||||
  void *hnd;
 | 
			
		||||
} PinosModuleImpl;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
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)
 | 
			
		||||
static char *
 | 
			
		||||
find_module (const char * path, const char *name)
 | 
			
		||||
{
 | 
			
		||||
  gchar *filename;
 | 
			
		||||
  GDir *dir;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +86,7 @@ find_module (const gchar * path, const gchar *name)
 | 
			
		|||
 * @core: a #PinosCore
 | 
			
		||||
 * @name: name of the module to load
 | 
			
		||||
 * @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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -123,96 +96,95 @@ PinosModule *
 | 
			
		|||
pinos_module_load (PinosCore    *core,
 | 
			
		||||
                   const gchar  *name,
 | 
			
		||||
                   const gchar  *args,
 | 
			
		||||
                   GError      **err)
 | 
			
		||||
                   char        **err)
 | 
			
		||||
{
 | 
			
		||||
  PinosModule *this;
 | 
			
		||||
  PinosModuleImpl *impl;
 | 
			
		||||
  GModule *gmodule;
 | 
			
		||||
  gchar *filename = NULL;
 | 
			
		||||
  const gchar *module_dir;
 | 
			
		||||
  void *hnd;
 | 
			
		||||
  char *filename = NULL;
 | 
			
		||||
  const char *module_dir;
 | 
			
		||||
  PinosModuleInitFunc init_func;
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (name != NULL && name[0] != '\0', NULL);
 | 
			
		||||
  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");
 | 
			
		||||
  module_dir = getenv ("PINOS_MODULE_DIR");
 | 
			
		||||
  if (module_dir != NULL) {
 | 
			
		||||
    gchar **l;
 | 
			
		||||
    gint i;
 | 
			
		||||
    char **l;
 | 
			
		||||
    int i, n_paths;
 | 
			
		||||
 | 
			
		||||
    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++) {
 | 
			
		||||
      filename = find_module (l[i], name);
 | 
			
		||||
      if (filename != NULL)
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    g_strfreev (l);
 | 
			
		||||
    pinos_free_strv (l);
 | 
			
		||||
  } else {
 | 
			
		||||
    pinos_log_debug ("moduledir set to: %s", MODULEDIR);
 | 
			
		||||
 | 
			
		||||
    filename = find_module (MODULEDIR, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (filename == NULL) {
 | 
			
		||||
    g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_NOT_FOUND,
 | 
			
		||||
        "No module \"%s\" was found", name);
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
  if (filename == NULL)
 | 
			
		||||
    goto not_found;
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("trying to load module: %s (%s)", name, filename);
 | 
			
		||||
 | 
			
		||||
  gmodule = g_module_open (filename, G_MODULE_BIND_LOCAL);
 | 
			
		||||
  g_free (filename);
 | 
			
		||||
  hnd = dlopen (filename, RTLD_NOW | RTLD_LOCAL);
 | 
			
		||||
  free (filename);
 | 
			
		||||
 | 
			
		||||
  if (gmodule == NULL) {
 | 
			
		||||
    g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_LOADING,
 | 
			
		||||
        "Failed to open module: %s", g_module_error ());
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
  if (hnd == NULL)
 | 
			
		||||
    goto open_failed;
 | 
			
		||||
 | 
			
		||||
  if (!g_module_symbol (gmodule, PINOS_SYMBOL_MODULE_INIT,
 | 
			
		||||
          (gpointer *) &init_func)) {
 | 
			
		||||
    g_set_error (err, PINOS_MODULE_ERROR, PINOS_MODULE_ERROR_LOADING,
 | 
			
		||||
        "\"%s\" is not a pinos module", name);
 | 
			
		||||
    g_module_close (gmodule);
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
  if ((init_func = dlsym (hnd, PINOS_SYMBOL_MODULE_INIT)) == NULL)
 | 
			
		||||
    goto no_pinos_module;
 | 
			
		||||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosModuleImpl));
 | 
			
		||||
  impl->module = gmodule;
 | 
			
		||||
  impl->hnd = hnd;
 | 
			
		||||
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  this->name = strdup (name);
 | 
			
		||||
  this->core = core;
 | 
			
		||||
 | 
			
		||||
  impl->ifaces[0].type = impl->core->registry.uri.module;
 | 
			
		||||
  impl->ifaces[0].iface = this;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
  if (!init_func (this, (gchar *) args))
 | 
			
		||||
    goto init_failed;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,47 +21,20 @@
 | 
			
		|||
#ifndef __PINOS_MODULE_H__
 | 
			
		||||
#define __PINOS_MODULE_H__
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
 | 
			
		||||
struct _PinosModule {
 | 
			
		||||
  SpaList link;
 | 
			
		||||
  gchar *name;
 | 
			
		||||
  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:
 | 
			
		||||
 * @module: A #PinosModule
 | 
			
		||||
| 
						 | 
				
			
			@ -70,14 +43,15 @@ typedef enum
 | 
			
		|||
 * A module should provide an init function with this signature. This function
 | 
			
		||||
 * will be called when a module is loaded.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %TRUE on success, %FALSE otherwise
 | 
			
		||||
 * 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 *args,
 | 
			
		||||
                                                  GError **err);
 | 
			
		||||
                                                  char       **err);
 | 
			
		||||
void              pinos_module_destroy           (PinosModule *module);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ new_pinos_port (PinosNode *node, PinosDirection direction, uint32_t port)
 | 
			
		|||
  np->direction = direction;
 | 
			
		||||
  np->port = port;
 | 
			
		||||
  np->links = g_ptr_array_new ();
 | 
			
		||||
  pinos_signal_init (&np->destroy_signal);
 | 
			
		||||
  return np;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,16 +53,10 @@ free_node_port (PinosPort *np)
 | 
			
		|||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosNode node;
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
  PinosInterface ifaces[1];
 | 
			
		||||
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  PinosDaemon *daemon;
 | 
			
		||||
  PinosNode1 *iface;
 | 
			
		||||
  PinosNode this;
 | 
			
		||||
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
  gchar *object_path;
 | 
			
		||||
  PinosNode1 *iface;
 | 
			
		||||
 | 
			
		||||
  uint32_t seq;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,8 +69,6 @@ typedef struct
 | 
			
		|||
  GError *error;
 | 
			
		||||
  guint idle_timeout;
 | 
			
		||||
 | 
			
		||||
  PinosDataLoop *data_loop;
 | 
			
		||||
 | 
			
		||||
  struct {
 | 
			
		||||
    GPtrArray *links;
 | 
			
		||||
  } rt;
 | 
			
		||||
| 
						 | 
				
			
			@ -87,7 +80,7 @@ static void init_complete (PinosNode *this);
 | 
			
		|||
static void
 | 
			
		||||
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;
 | 
			
		||||
  guint n_input_ports, n_output_ports, max_input_ports, max_output_ports;
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
      if (!impl->async_init)
 | 
			
		||||
        pinos_signal_emit (&node->port_added, node, np);
 | 
			
		||||
        pinos_signal_emit (&node->core->port_added, node, np);
 | 
			
		||||
      i++;
 | 
			
		||||
    } else if (p) {
 | 
			
		||||
      GList *next;
 | 
			
		||||
| 
						 | 
				
			
			@ -141,7 +134,7 @@ update_port_ids (PinosNode *node, gboolean create)
 | 
			
		|||
      ports = next;
 | 
			
		||||
 | 
			
		||||
      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);
 | 
			
		||||
    } else
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +157,7 @@ update_port_ids (PinosNode *node, gboolean create)
 | 
			
		|||
      impl->output_ports = g_list_insert_before (impl->output_ports, ports, np);
 | 
			
		||||
 | 
			
		||||
      if (!impl->async_init)
 | 
			
		||||
        pinos_signal_emit (&node->port_added, node, np);
 | 
			
		||||
        pinos_signal_emit (&node->core->port_added, node, np);
 | 
			
		||||
      i++;
 | 
			
		||||
    } else if (p) {
 | 
			
		||||
      GList *next;
 | 
			
		||||
| 
						 | 
				
			
			@ -175,7 +168,7 @@ update_port_ids (PinosNode *node, gboolean create)
 | 
			
		|||
      ports = next;
 | 
			
		||||
 | 
			
		||||
      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);
 | 
			
		||||
    } else
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +189,7 @@ update_port_ids (PinosNode *node, gboolean create)
 | 
			
		|||
  for (i = 0; i < max_output_ports; 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
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +227,7 @@ start_node (PinosNode *this)
 | 
			
		|||
static SpaResult
 | 
			
		||||
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;
 | 
			
		||||
  GList *walk;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -326,7 +319,7 @@ static void
 | 
			
		|||
on_node_event (SpaNode *node, SpaNodeEvent *event, void *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) {
 | 
			
		||||
    case SPA_NODE_EVENT_TYPE_INVALID:
 | 
			
		||||
| 
						 | 
				
			
			@ -340,9 +333,8 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
 | 
			
		|||
      SpaNodeEventAsyncComplete *ac = (SpaNodeEventAsyncComplete *) event;
 | 
			
		||||
 | 
			
		||||
      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)) {
 | 
			
		||||
        PinosNodeAsyncCompleteData acd = { ac->seq, ac->res };
 | 
			
		||||
        pinos_signal_emit (&this->async_complete, this, &acd);
 | 
			
		||||
      if (!pinos_main_loop_defer_complete (this->core->main_loop, this, ac->seq, ac->res)) {
 | 
			
		||||
        pinos_signal_emit (&this->async_complete, this, ac->seq, ac->res);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -359,7 +351,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
 | 
			
		|||
          continue;
 | 
			
		||||
 | 
			
		||||
        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,
 | 
			
		||||
                         SPA_ID_INVALID,
 | 
			
		||||
                         sizeof (PinosLink *),
 | 
			
		||||
| 
						 | 
				
			
			@ -395,7 +387,7 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data)
 | 
			
		|||
          link->queue[offset] = po->buffer_id;
 | 
			
		||||
          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,
 | 
			
		||||
                           SPA_ID_INVALID,
 | 
			
		||||
                           sizeof (PinosLink *),
 | 
			
		||||
| 
						 | 
				
			
			@ -441,105 +433,41 @@ handle_remove (PinosNode1             *interface,
 | 
			
		|||
               gpointer                user_data)
 | 
			
		||||
{
 | 
			
		||||
  PinosNode *this = user_data;
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("node %p: remove", this);
 | 
			
		||||
  pinos_object_destroy (&this->object);
 | 
			
		||||
  pinos_node_destroy (this);
 | 
			
		||||
 | 
			
		||||
  g_dbus_method_invocation_return_value (invocation,
 | 
			
		||||
                                         g_variant_new ("()"));
 | 
			
		||||
  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
 | 
			
		||||
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);
 | 
			
		||||
  impl->async_init = FALSE;
 | 
			
		||||
  on_property_notify (G_OBJECT (this), NULL, this);
 | 
			
		||||
  impl->async_init = false;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
node_destroy (PinosObject * obj)
 | 
			
		||||
void
 | 
			
		||||
pinos_node_set_data_loop (PinosNode        *node,
 | 
			
		||||
                          PinosDataLoop    *loop)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (obj, PinosNodeImpl, object);
 | 
			
		||||
  PinosNode *this = &impl->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);
 | 
			
		||||
  node->data_loop = loop;
 | 
			
		||||
  pinos_signal_emit (&node->loop_changed, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosNode *
 | 
			
		||||
| 
						 | 
				
			
			@ -551,31 +479,26 @@ pinos_node_new (PinosCore       *core,
 | 
			
		|||
{
 | 
			
		||||
  PinosNodeImpl *impl;
 | 
			
		||||
  PinosNode *this;
 | 
			
		||||
  PinosObjectSkeleton *skel;
 | 
			
		||||
 | 
			
		||||
  impl = calloc (1, sizeof (PinosNodeImpl));
 | 
			
		||||
  impl->core = core;
 | 
			
		||||
  this = &impl->node;
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  this->core = core;
 | 
			
		||||
  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->properties = properties;
 | 
			
		||||
 | 
			
		||||
  this->node = node;
 | 
			
		||||
  this->clock = clock;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&this->state_change);
 | 
			
		||||
  pinos_signal_init (&this->port_added);
 | 
			
		||||
  pinos_signal_init (&this->port_removed);
 | 
			
		||||
  if (spa_node_set_event_callback (this->node, on_node_event, this) < 0)
 | 
			
		||||
    pinos_log_warn ("node %p: error setting callback", this);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
  pinos_signal_init (&this->async_complete);
 | 
			
		||||
  pinos_signal_init (&this->transport_changed);
 | 
			
		||||
  pinos_signal_init (&this->loop_changed);
 | 
			
		||||
 | 
			
		||||
  impl->iface = pinos_node1_skeleton_new ();
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  pinos_registry_add_object (&impl->core->registry, &impl->object);
 | 
			
		||||
 | 
			
		||||
  if (this->node->info) {
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -607,34 +528,53 @@ pinos_node_new (PinosCore       *core,
 | 
			
		|||
    init_complete (this);
 | 
			
		||||
  } else {
 | 
			
		||||
    impl->async_init = TRUE;
 | 
			
		||||
    pinos_main_loop_defer (impl->core->main_loop,
 | 
			
		||||
    pinos_main_loop_defer (this->core->main_loop,
 | 
			
		||||
                           this,
 | 
			
		||||
                           SPA_RESULT_RETURN_ASYNC (0),
 | 
			
		||||
                           (PinosDeferFunc) init_complete,
 | 
			
		||||
                           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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * pinos_node_get_daemon:
 | 
			
		||||
 * pinos_node_destroy:
 | 
			
		||||
 * @node: a #PinosNode
 | 
			
		||||
 *
 | 
			
		||||
 * Get the daemon of @node.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: the daemon of @node.
 | 
			
		||||
 * Remove @node. This will stop the transfer on the node and
 | 
			
		||||
 * free the resources allocated by @node.
 | 
			
		||||
 */
 | 
			
		||||
PinosDaemon *
 | 
			
		||||
pinos_node_get_daemon (PinosNode *node)
 | 
			
		||||
void
 | 
			
		||||
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 *
 | 
			
		||||
pinos_node_get_client (PinosNode *node)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
 | 
			
		||||
 | 
			
		||||
  g_return_val_if_fail (node, NULL);
 | 
			
		||||
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
 | 
			
		||||
  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:
 | 
			
		||||
| 
						 | 
				
			
			@ -703,7 +605,7 @@ PinosPort *
 | 
			
		|||
pinos_node_get_free_port (PinosNode       *node,
 | 
			
		||||
                          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;
 | 
			
		||||
  GList *ports, *walk;
 | 
			
		||||
  PinosPort *port = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -751,7 +653,7 @@ do_add_link (SpaPoll        *poll,
 | 
			
		|||
             void           *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];
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  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_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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -826,15 +728,13 @@ pinos_port_link (PinosPort       *output_port,
 | 
			
		|||
 | 
			
		||||
  link = find_link (output_port, input_port);
 | 
			
		||||
 | 
			
		||||
  if (link)  {
 | 
			
		||||
    g_object_ref (link);
 | 
			
		||||
  } else {
 | 
			
		||||
  if (link == NULL)  {
 | 
			
		||||
    input_node->live = output_node->live;
 | 
			
		||||
    if (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);
 | 
			
		||||
 | 
			
		||||
    link = pinos_link_new (output_impl->core,
 | 
			
		||||
    link = pinos_link_new (output_node->core,
 | 
			
		||||
                           output_port,
 | 
			
		||||
                           input_port,
 | 
			
		||||
                           format_filter,
 | 
			
		||||
| 
						 | 
				
			
			@ -846,13 +746,13 @@ pinos_port_link (PinosPort       *output_port,
 | 
			
		|||
    output_impl->n_used_output_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,
 | 
			
		||||
                     SPA_ID_INVALID,
 | 
			
		||||
                     sizeof (PinosLink *),
 | 
			
		||||
                     &link,
 | 
			
		||||
                     output_node);
 | 
			
		||||
    spa_poll_invoke (&input_impl->data_loop->poll,
 | 
			
		||||
    spa_poll_invoke (&input_node->data_loop->poll,
 | 
			
		||||
                     do_add_link,
 | 
			
		||||
                     SPA_ID_INVALID,
 | 
			
		||||
                     sizeof (PinosLink *),
 | 
			
		||||
| 
						 | 
				
			
			@ -902,7 +802,7 @@ do_remove_link_done (SpaPoll        *poll,
 | 
			
		|||
{
 | 
			
		||||
  PinosPort *port = user_data;
 | 
			
		||||
  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];
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("port %p: finish unlink", port);
 | 
			
		||||
| 
						 | 
				
			
			@ -931,7 +831,7 @@ do_remove_link_done (SpaPoll        *poll,
 | 
			
		|||
    port->n_buffers = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pinos_main_loop_defer_complete (impl->core->main_loop,
 | 
			
		||||
  pinos_main_loop_defer_complete (this->core->main_loop,
 | 
			
		||||
                                  port,
 | 
			
		||||
                                  seq,
 | 
			
		||||
                                  SPA_RESULT_OK);
 | 
			
		||||
| 
						 | 
				
			
			@ -951,7 +851,7 @@ do_remove_link (SpaPoll        *poll,
 | 
			
		|||
{
 | 
			
		||||
  PinosPort *port = user_data;
 | 
			
		||||
  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];
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -962,7 +862,7 @@ do_remove_link (SpaPoll        *poll,
 | 
			
		|||
 | 
			
		||||
  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,
 | 
			
		||||
                         seq,
 | 
			
		||||
                         sizeof (PinosLink *),
 | 
			
		||||
| 
						 | 
				
			
			@ -975,13 +875,13 @@ SpaResult
 | 
			
		|||
pinos_port_unlink (PinosPort *port, PinosLink *link)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  g_object_ref (link);
 | 
			
		||||
  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,
 | 
			
		||||
                         impl->seq++,
 | 
			
		||||
                         sizeof (PinosLink *),
 | 
			
		||||
| 
						 | 
				
			
			@ -1000,7 +900,6 @@ do_clear_buffers_done (SpaPoll        *poll,
 | 
			
		|||
{
 | 
			
		||||
  PinosPort *port = user_data;
 | 
			
		||||
  PinosNode *this = port->node;
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("port %p: clear buffers finish", port);
 | 
			
		||||
| 
						 | 
				
			
			@ -1012,7 +911,7 @@ do_clear_buffers_done (SpaPoll        *poll,
 | 
			
		|||
  port->buffers = NULL;
 | 
			
		||||
  port->n_buffers = 0;
 | 
			
		||||
 | 
			
		||||
  pinos_main_loop_defer_complete (impl->core->main_loop,
 | 
			
		||||
  pinos_main_loop_defer_complete (this->core->main_loop,
 | 
			
		||||
                                  port,
 | 
			
		||||
                                  seq,
 | 
			
		||||
                                  res);
 | 
			
		||||
| 
						 | 
				
			
			@ -1029,12 +928,11 @@ do_clear_buffers (SpaPoll        *poll,
 | 
			
		|||
{
 | 
			
		||||
  PinosPort *port = user_data;
 | 
			
		||||
  PinosNode *this = port->node;
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, node);
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
 | 
			
		||||
  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,
 | 
			
		||||
                         seq,
 | 
			
		||||
                         0, NULL,
 | 
			
		||||
| 
						 | 
				
			
			@ -1046,10 +944,10 @@ SpaResult
 | 
			
		|||
pinos_port_clear_buffers (PinosPort *port)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
  res = spa_poll_invoke (&impl->data_loop->poll,
 | 
			
		||||
  res = spa_poll_invoke (&port->node->data_loop->poll,
 | 
			
		||||
                         do_clear_buffers,
 | 
			
		||||
                         impl->seq++,
 | 
			
		||||
                         0, NULL,
 | 
			
		||||
| 
						 | 
				
			
			@ -1070,7 +968,7 @@ GList *
 | 
			
		|||
pinos_node_get_ports (PinosNode *node, PinosDirection direction)
 | 
			
		||||
{
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1085,7 +983,7 @@ pinos_node_get_ports (PinosNode *node, PinosDirection direction)
 | 
			
		|||
static void
 | 
			
		||||
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) {
 | 
			
		||||
    g_source_remove (impl->idle_timeout);
 | 
			
		||||
| 
						 | 
				
			
			@ -1124,7 +1022,6 @@ SpaResult
 | 
			
		|||
pinos_node_set_state (PinosNode      *node,
 | 
			
		||||
                      PinosNodeState  state)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
 | 
			
		||||
  SpaResult res = SPA_RESULT_OK;
 | 
			
		||||
 | 
			
		||||
  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))
 | 
			
		||||
    return res;
 | 
			
		||||
 | 
			
		||||
  pinos_main_loop_defer (impl->core->main_loop,
 | 
			
		||||
  pinos_main_loop_defer (node->core->main_loop,
 | 
			
		||||
                         node,
 | 
			
		||||
                         res,
 | 
			
		||||
                         (PinosDeferFunc) on_state_complete,
 | 
			
		||||
| 
						 | 
				
			
			@ -1181,22 +1078,20 @@ void
 | 
			
		|||
pinos_node_update_state (PinosNode      *node,
 | 
			
		||||
                         PinosNodeState  state)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
 | 
			
		||||
  PinosNodeState old;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (node);
 | 
			
		||||
 | 
			
		||||
  old = node->state;
 | 
			
		||||
  if (old != state) {
 | 
			
		||||
    PinosNodeStateChangeData sc = { old, state };
 | 
			
		||||
 | 
			
		||||
    pinos_log_debug ("node %p: update state from %s -> %s", node,
 | 
			
		||||
        pinos_node_state_as_string (old),
 | 
			
		||||
        pinos_node_state_as_string (state));
 | 
			
		||||
 | 
			
		||||
    node->state = 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,
 | 
			
		||||
                         GError    *error)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
 | 
			
		||||
  PinosNodeStateChangeData sc;
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
 | 
			
		||||
  PinosNodeState old;
 | 
			
		||||
 | 
			
		||||
  g_return_if_fail (node);
 | 
			
		||||
 | 
			
		||||
  g_clear_error (&impl->error);
 | 
			
		||||
  remove_idle_timeout (node);
 | 
			
		||||
  impl->error = error;
 | 
			
		||||
  sc.old = node->state;
 | 
			
		||||
  sc.state = node->state = PINOS_NODE_STATE_ERROR;
 | 
			
		||||
  old = node->state;
 | 
			
		||||
  node->state = PINOS_NODE_STATE_ERROR;
 | 
			
		||||
  pinos_log_debug ("node %p: got error state %s", node, error->message);
 | 
			
		||||
  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
 | 
			
		||||
idle_timeout (PinosNode *node)
 | 
			
		||||
{
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, node);
 | 
			
		||||
  PinosNodeImpl *impl = SPA_CONTAINER_OF (node, PinosNodeImpl, this);
 | 
			
		||||
 | 
			
		||||
  impl->idle_timeout = 0;
 | 
			
		||||
  pinos_log_debug ("node %p: idle timeout", node);
 | 
			
		||||
| 
						 | 
				
			
			@ -1248,7 +1143,7 @@ idle_timeout (PinosNode *node)
 | 
			
		|||
void
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,11 +27,8 @@ G_BEGIN_DECLS
 | 
			
		|||
#define PINOS_NODE_URI                            "http://pinos.org/ns/node"
 | 
			
		||||
#define PINOS_NODE_PREFIX                         PINOS_NODE_URI "#"
 | 
			
		||||
 | 
			
		||||
#define PINOS_PORT_URI                            PINOS_NODE_PREFIX "Port"
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosPort PinosPort;
 | 
			
		||||
typedef struct _PinosNode PinosNode;
 | 
			
		||||
typedef struct _PinosNodeListener PinosNodeListener;
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/node.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,9 +39,10 @@ typedef struct _PinosNodeListener PinosNodeListener;
 | 
			
		|||
#include <pinos/server/daemon.h>
 | 
			
		||||
#include <pinos/server/link.h>
 | 
			
		||||
#include <pinos/server/client.h>
 | 
			
		||||
#include <pinos/server/data-loop.h>
 | 
			
		||||
 | 
			
		||||
struct _PinosPort {
 | 
			
		||||
  PinosObject     object;
 | 
			
		||||
  PINOS_SIGNAL   (destroy_signal, (PinosListener *listener, PinosPort *));
 | 
			
		||||
 | 
			
		||||
  PinosNode      *node;
 | 
			
		||||
  PinosDirection  direction;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,12 +72,16 @@ typedef struct {
 | 
			
		|||
 * Pinos node class.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosNode {
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  SpaList    list;
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  char *name;
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
  PinosNodeState state;
 | 
			
		||||
 | 
			
		||||
  SpaHandle *handle;
 | 
			
		||||
  SpaNode *node;
 | 
			
		||||
 | 
			
		||||
  bool live;
 | 
			
		||||
  SpaClock *clock;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,12 +89,20 @@ struct _PinosNode {
 | 
			
		|||
  gboolean have_outputs;
 | 
			
		||||
 | 
			
		||||
  PinosTransport *transport;
 | 
			
		||||
  PinosSignal transport_changed;
 | 
			
		||||
  PINOS_SIGNAL (transport_changed, (PinosListener *listener,
 | 
			
		||||
                                    PinosNode     *object));
 | 
			
		||||
 | 
			
		||||
  PinosSignal state_change;
 | 
			
		||||
  PinosSignal port_added;
 | 
			
		||||
  PinosSignal port_removed;
 | 
			
		||||
  PinosSignal async_complete;
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosNode     *object));
 | 
			
		||||
 | 
			
		||||
  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,
 | 
			
		||||
                                  PinosDirection    direction);
 | 
			
		||||
| 
						 | 
				
			
			@ -103,37 +113,18 @@ struct _PinosNode {
 | 
			
		|||
                                  PinosNodeState    state);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _PinosNodeListener {
 | 
			
		||||
  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,
 | 
			
		||||
PinosNode *         pinos_node_new                     (PinosCore       *core,
 | 
			
		||||
                                                        const char      *name,
 | 
			
		||||
                                                        SpaNode         *node,
 | 
			
		||||
                                                        SpaClock        *clock,
 | 
			
		||||
                                                        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);
 | 
			
		||||
const gchar *       pinos_node_get_object_path         (PinosNode        *node);
 | 
			
		||||
 | 
			
		||||
PinosPort *         pinos_node_get_free_port           (PinosNode        *node,
 | 
			
		||||
                                                        PinosDirection    direction);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,13 +34,11 @@ pinos_registry_init (PinosRegistry *reg)
 | 
			
		|||
{
 | 
			
		||||
  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.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.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.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.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);
 | 
			
		||||
 | 
			
		||||
  pinos_map_init (®->objects, 512);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (®->object_added);
 | 
			
		||||
  pinos_signal_init (®->object_removed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosObject *
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +60,7 @@ pinos_registry_iterate_objects (PinosRegistry *reg,
 | 
			
		|||
    idx = SPA_PTR_TO_INT (*state);
 | 
			
		||||
    *state = SPA_INT_TO_PTR (idx+1);
 | 
			
		||||
    o = pinos_map_lookup (®->objects, idx);
 | 
			
		||||
    if (o != NULL && (type == SPA_ID_INVALID || o->type == type))
 | 
			
		||||
    if (o != NULL)
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,15 +35,13 @@ extern "C" {
 | 
			
		|||
typedef struct _PinosRegistry PinosRegistry;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  uint32_t core;
 | 
			
		||||
  uint32_t daemon;
 | 
			
		||||
  uint32_t registry;
 | 
			
		||||
  uint32_t node;
 | 
			
		||||
  uint32_t port;
 | 
			
		||||
  uint32_t link;
 | 
			
		||||
  uint32_t node_factory;
 | 
			
		||||
  uint32_t link;
 | 
			
		||||
  uint32_t client;
 | 
			
		||||
  uint32_t monitor;
 | 
			
		||||
 | 
			
		||||
  uint32_t spa_node;
 | 
			
		||||
  uint32_t spa_clock;
 | 
			
		||||
  uint32_t spa_monitor;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,35 +53,13 @@ typedef struct {
 | 
			
		|||
 * Pinos registry struct.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosRegistry {
 | 
			
		||||
  PinosObject object;
 | 
			
		||||
 | 
			
		||||
  SpaIDMap *map;
 | 
			
		||||
  PinosURI uri;
 | 
			
		||||
  PinosMap objects;
 | 
			
		||||
 | 
			
		||||
  PinosSignal object_added;
 | 
			
		||||
  PinosSignal object_removed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void pinos_registry_init (PinosRegistry *reg);
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_registry_add_object (PinosRegistry *reg,
 | 
			
		||||
                           PinosObject   *object)
 | 
			
		||||
{
 | 
			
		||||
  object->id = pinos_map_insert_new (®->objects, object);
 | 
			
		||||
  pinos_signal_emit (®->object_added, reg, object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
pinos_registry_remove_object (PinosRegistry *reg,
 | 
			
		||||
                              PinosObject   *object)
 | 
			
		||||
{
 | 
			
		||||
  pinos_signal_emit (®->object_removed, reg, object);
 | 
			
		||||
  pinos_map_remove (®->objects, object->id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PinosObject *    pinos_registry_iterate_objects         (PinosRegistry *reg,
 | 
			
		||||
                                                         uint32_t       type,
 | 
			
		||||
                                                         void         **state);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,12 +34,13 @@ typedef enum {
 | 
			
		|||
  SPA_RESULT_MODIFIED                  =  1,
 | 
			
		||||
  SPA_RESULT_OK                        =  0,
 | 
			
		||||
  SPA_RESULT_ERROR                     = -1,
 | 
			
		||||
  SPA_RESULT_INACTIVE                  = -2,
 | 
			
		||||
  SPA_RESULT_NO_FORMAT                 = -3,
 | 
			
		||||
  SPA_RESULT_INVALID_COMMAND           = -4,
 | 
			
		||||
  SPA_RESULT_INVALID_PORT              = -5,
 | 
			
		||||
  SPA_RESULT_HAVE_ENOUGH_INPUT         = -6,
 | 
			
		||||
  SPA_RESULT_NEED_MORE_INPUT           = -7,
 | 
			
		||||
  SPA_RESULT_ERRNO                     = -2,
 | 
			
		||||
  SPA_RESULT_INACTIVE                  = -3,
 | 
			
		||||
  SPA_RESULT_NO_FORMAT                 = -4,
 | 
			
		||||
  SPA_RESULT_INVALID_COMMAND           = -5,
 | 
			
		||||
  SPA_RESULT_INVALID_PORT              = -6,
 | 
			
		||||
  SPA_RESULT_HAVE_ENOUGH_INPUT         = -7,
 | 
			
		||||
  SPA_RESULT_NEED_MORE_INPUT           = -8,
 | 
			
		||||
  SPA_RESULT_PORTS_CHANGED             = -9,
 | 
			
		||||
  SPA_RESULT_FORMAT_CHANGED            = -10,
 | 
			
		||||
  SPA_RESULT_PROPERTIES_CHANGED        = -11,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -515,6 +515,7 @@ spa_v4l2_source_node_port_enum_formats (SpaNode         *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))
 | 
			
		||||
    return SPA_RESULT_INVALID_PORT;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue