mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
Initial commit
This commit is contained in:
commit
3fba92fb74
41 changed files with 5544 additions and 0 deletions
3
src/.gitignore
vendored
Normal file
3
src/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pulsevideo
|
||||
test-client
|
||||
test-subscribe
|
||||
228
src/Makefile.am
Normal file
228
src/Makefile.am
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
# This file is part of PulseVideo.
|
||||
#
|
||||
# Copyright 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
#
|
||||
# PulseVideo is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseVideo 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
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseVideo; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
###################################
|
||||
# Extra directories #
|
||||
###################################
|
||||
|
||||
pulsevideoincludedir=$(includedir)/client
|
||||
pulsevideoserverincludedir=$(includedir)/server
|
||||
pulsevideolibexecdir=$(libexecdir)/client
|
||||
dbuspolicydir=$(sysconfdir)/dbus-1/system.d
|
||||
|
||||
###################################
|
||||
# Compiler/linker flags #
|
||||
###################################
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/src/modules \
|
||||
-I$(top_builddir)/src/modules \
|
||||
-DPV_SRCDIR=\"$(abs_srcdir)\" \
|
||||
-DPV_BUILDDIR=\"$(abs_builddir)\"
|
||||
AM_CFLAGS = $(GLIB_CFLAGS) $(GST_CFLAGS)
|
||||
AM_CXXFLAGS = $(AM_CFLAGS)
|
||||
SERVER_CFLAGS = -D__INCLUDED_FROM_PULSE_VIDEO
|
||||
|
||||
AM_LIBADD = $(GLIB_LIBS) $(INTLLIBS) $(GST_LIBS)
|
||||
AM_LDADD = $(GLIB_LIBS) $(GST_LIBS) $(INTLLIBS)
|
||||
AM_LDFLAGS = $(NODELETE_LDFLAGS)
|
||||
|
||||
FOREIGN_CFLAGS = -w
|
||||
|
||||
###################################
|
||||
# Extra files #
|
||||
###################################
|
||||
|
||||
EXTRA_DIST = \
|
||||
src/version.h.in \
|
||||
daemon/pulsevideo-system.conf
|
||||
|
||||
dbuspolicy_DATA = \
|
||||
daemon/pulsevideo-system.conf
|
||||
|
||||
###################################
|
||||
# Includes #
|
||||
###################################
|
||||
|
||||
enumtypesincludes = client/pv-context.h \
|
||||
client/pv-stream.h \
|
||||
client/pv-subscribe.h
|
||||
|
||||
client/pv-enumtypes.h: $(enumtypesincludes)
|
||||
$(AM_V_GEN)$(GLIB_MKENUMS) \
|
||||
--fhead "#ifndef __PV_ENUM_TYPES_H__\n#define __PV_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
|
||||
--fprod "\n/* enumerations from \"@filename@\" */\n" \
|
||||
--vhead "GType @enum_name@_get_type (void);\n#define PV_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \
|
||||
--ftail "G_END_DECLS\n\n#endif /* __PV_ENUM_TYPES_H__ */" \
|
||||
$^ > client/pv-enumtypes.h
|
||||
|
||||
client/pv-enumtypes.c: $(enumtypesincludes) client/pv-enumtypes.h
|
||||
$(AM_V_GEN)$(GLIB_MKENUMS) \
|
||||
--fhead "#include \"pv-enumtypes.h\"\n#include <client/pulsevideo.h>\n#define C_ENUM(v) ((gint) v)\n#define C_FLAGS(v) ((guint) v)\n " \
|
||||
--fprod "\n/* enumerations from \"@filename@\" */" \
|
||||
--vhead "GType\n@enum_name@_get_type (void)\n{\n static gsize id = 0;\n static const G@Type@Value values[] = {" \
|
||||
--vprod " { C_@TYPE@(@VALUENAME@), \"@VALUENAME@\", \"@valuenick@\" }," \
|
||||
--vtail " { 0, NULL, NULL }\n };\n\n if (g_once_init_enter (&id)) {\n GType tmp = g_@type@_register_static (\"@EnumName@\", values);\n g_once_init_leave (&id, tmp);\n }\n\n return (GType) id;\n}" \
|
||||
$^ > client/pv-enumtypes.c
|
||||
|
||||
|
||||
dbus/org-pulsevideo.c: dbus/org-pulsevideo.h
|
||||
dbus/org-pulsevideo.h: dbus/org.pulsevideo.xml
|
||||
$(AM_V_GEN) $(GDBUS_CODEGEN) \
|
||||
--c-generate-object-manager \
|
||||
--interface-prefix org.pulsevideo. \
|
||||
--generate-c-code dbus/org-pulsevideo \
|
||||
--generate-docbook ../doc/org-pulsevideo \
|
||||
--c-namespace Pv dbus/org.pulsevideo.xml
|
||||
|
||||
built_header_make = client/pv-enumtypes.h dbus/org-pulsevideo.h
|
||||
built_source_make = client/pv-enumtypes.c dbus/org-pulsevideo.c
|
||||
|
||||
BUILT_SOURCES = $(built_header_make) \
|
||||
$(built_source_make)
|
||||
|
||||
CLEANFILES = $(built_header_make) $(built_source_make)
|
||||
|
||||
###################################
|
||||
# Main daemon #
|
||||
###################################
|
||||
|
||||
bin_PROGRAMS = pulsevideo
|
||||
|
||||
pulsevideo_SOURCES = \
|
||||
daemon/main.c
|
||||
|
||||
pulsevideo_CFLAGS = $(AM_CFLAGS)
|
||||
pulsevideo_LDADD = $(AM_LDADD) libpulsevideocore-@PV_MAJORMINOR@.la libpulsevideo-@PV_MAJORMINOR@.la $(LIBLTDL)
|
||||
# This is needed because automake doesn't properly expand the foreach below
|
||||
pulsevideo_DEPENDENCIES = libpulsevideocore-@PV_MAJORMINOR@.la libpulsevideo-@PV_MAJORMINOR@.la
|
||||
pulsevideo_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(IMMEDIATE_LDFLAGS)
|
||||
|
||||
###################################
|
||||
# Test programs #
|
||||
###################################
|
||||
noinst_LTLIBRARIES =
|
||||
|
||||
TESTS_default =
|
||||
|
||||
TESTS_norun = test-client \
|
||||
test-subscribe
|
||||
|
||||
# These tests need a running pulsevideo daemon
|
||||
TESTS_daemon =
|
||||
|
||||
noinst_PROGRAMS = $(TESTS_default) $(TESTS_norun) $(TESTS_daemon)
|
||||
|
||||
test_client_SOURCES = tests/test-client.c
|
||||
test_client_CFLAGS = $(AM_CFLAGS)
|
||||
test_client_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la
|
||||
test_client_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
||||
|
||||
test_subscribe_SOURCES = tests/test-subscribe.c
|
||||
test_subscribe_CFLAGS = $(AM_CFLAGS)
|
||||
test_subscribe_LDADD = $(AM_LDADD) libpulsevideo-@PV_MAJORMINOR@.la
|
||||
test_subscribe_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
||||
|
||||
###################################
|
||||
# Client library #
|
||||
###################################
|
||||
|
||||
pulsevideoinclude_HEADERS = \
|
||||
client/pv-context.h \
|
||||
client/pv-enumtypes.h \
|
||||
client/pv-stream.h \
|
||||
client/pv-subscribe.h \
|
||||
client/pv-subscribe.h \
|
||||
dbus/org-pulsevideo.h
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libpulsevideo-@PV_MAJORMINOR@.la
|
||||
|
||||
# Public interface
|
||||
libpulsevideo_@PV_MAJORMINOR@_la_SOURCES = \
|
||||
client/pv-context.h client/pv-context.c \
|
||||
client/pv-enumtypes.h client/pv-enumtypes.c \
|
||||
client/pv-stream.h client/pv-stream.c \
|
||||
dbus/org-pulsevideo.c
|
||||
|
||||
|
||||
libpulsevideo_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)
|
||||
libpulsevideo_@PV_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
||||
libpulsevideo_@PV_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV)
|
||||
|
||||
###################################
|
||||
# Daemon core library #
|
||||
###################################
|
||||
|
||||
lib_LTLIBRARIES += libpulsevideocore-@PV_MAJORMINOR@.la
|
||||
|
||||
# Pure core stuff
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \
|
||||
server/pv-client.c server/pv-client.h \
|
||||
server/pv-daemon.c server/pv-daemon.h \
|
||||
server/pv-source-output.c server/pv-source-output.h \
|
||||
server/pv-source.c server/pv-source.h \
|
||||
modules/v4l2/pv-v4l2-source.c
|
||||
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS)
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LTLIBICONV)
|
||||
|
||||
###################################
|
||||
# Some minor stuff #
|
||||
###################################
|
||||
|
||||
DISTCLEANFILES =
|
||||
|
||||
install-exec-hook:
|
||||
rm -f $(DESTDIR)$(modlibexecdir)/*.la
|
||||
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(modlibexecdir)/*.so
|
||||
|
||||
# Automatically generate linker version script. We use the same one for all public .sos
|
||||
update-map-file:
|
||||
( echo "PULSE_0 {" ; \
|
||||
echo "global:" ; \
|
||||
ctags -I PV_GCC_MALLOC,PV_GCC_ALLOC_SIZE2,PV_GCC_ALLOC_SIZE,PV_GCC_PURE,PV_GCC_CONST,PV_GCC_DEPRECATED,PV_GCC_PRINTF_ATTR -f - --c-kinds=p $(pulsevideoinclude_HEADERS) | awk '/^pa_/ { print $$1 ";" }' | sort ; \
|
||||
echo "local:" ; \
|
||||
echo "*;" ; \
|
||||
echo "};" ) > $(srcdir)/map-file
|
||||
|
||||
update-all: update-map-file
|
||||
|
||||
# Force installation order of libraries. libtool relinks on install time, in
|
||||
# which case libpulsecommon has to be installed before others, but the padsp
|
||||
# preload library has to be done after the normal libraries (e.g. libpulse)
|
||||
# ...
|
||||
# Unfortunately automake behaviour means that rules without commands also
|
||||
# override build-in rules, so it's not trivial to add dependencies.
|
||||
# See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328 for the workaround
|
||||
# ...
|
||||
# Isn't libtool/autotools fun!
|
||||
|
||||
installlibLTLIBRARIES = install-libLTLIBRARIES
|
||||
$(installlibLTLIBRARIES): install-pkglibLTLIBRARIES
|
||||
|
||||
installmodlibexecLTLIBRARIES = install-modlibexecLTLIBRARIES
|
||||
$(installmodlibexecLTLIBRARIES): install-pkglibLTLIBRARIES
|
||||
|
||||
installpadsplibLTLIBRARIES = install-padsplibLTLIBRARIES
|
||||
$(installpadsplibLTLIBRARIES): install-libLTLIBRARIES
|
||||
|
||||
.PHONY: update-all update-map-file coverage
|
||||
2
src/client/.gitignore
vendored
Normal file
2
src/client/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pv-enumtypes.c
|
||||
pv-enumtypes.h
|
||||
28
src/client/pulsevideo.h
Normal file
28
src/client/pulsevideo.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PULSEVIDEO_H__
|
||||
#define __PULSEVIDEO_H__
|
||||
|
||||
#include <client/pv-context.h>
|
||||
#include <client/pv-stream.h>
|
||||
#include <client/pv-subscribe.h>
|
||||
|
||||
#endif /* __PULSEVIDEO_H__ */
|
||||
|
||||
502
src/client/pv-context.c
Normal file
502
src/client/pv-context.c
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
/* Pulsevideo
|
||||
* 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 "server/pv-daemon.h"
|
||||
|
||||
#include "client/pv-context.h"
|
||||
#include "client/pv-enumtypes.h"
|
||||
#include "client/pv-subscribe.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
struct _PvContextPrivate
|
||||
{
|
||||
gchar *name;
|
||||
GVariant *properties;
|
||||
|
||||
guint id;
|
||||
GDBusConnection *connection;
|
||||
|
||||
PvContextFlags flags;
|
||||
PvContextState state;
|
||||
|
||||
PvDaemon1 *daemon;
|
||||
|
||||
gchar *client_path;
|
||||
PvClient1 *client;
|
||||
|
||||
PvSubscriptionFlags subscription_mask;
|
||||
GDBusObjectManager *client_manager;
|
||||
};
|
||||
|
||||
|
||||
#define PV_CONTEXT_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_CONTEXT, PvContextPrivate))
|
||||
|
||||
G_DEFINE_TYPE (PvContext, pv_context, G_TYPE_OBJECT);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_NAME,
|
||||
PROP_PROPERTIES,
|
||||
PROP_STATE,
|
||||
PROP_SUBSCRIPTION_MASK,
|
||||
PROP_CONNECTION,
|
||||
PROP_CLIENT_PATH
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_SUBSCRIPTION_EVENT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
#include "pv-subscribe.c"
|
||||
|
||||
static void
|
||||
pv_context_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvContext *context = PV_CONTEXT (_object);
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, priv->name);
|
||||
break;
|
||||
|
||||
case PROP_PROPERTIES:
|
||||
g_value_set_variant (value, priv->properties);
|
||||
break;
|
||||
|
||||
case PROP_STATE:
|
||||
g_value_set_enum (value, priv->state);
|
||||
break;
|
||||
|
||||
case PROP_SUBSCRIPTION_MASK:
|
||||
g_value_set_flags (value, priv->subscription_mask);
|
||||
break;
|
||||
|
||||
case PROP_CONNECTION:
|
||||
g_value_set_object (value, priv->connection);
|
||||
break;
|
||||
|
||||
case PROP_CLIENT_PATH:
|
||||
g_value_set_string (value, priv->client_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_context_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvContext *context = PV_CONTEXT (_object);
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_NAME:
|
||||
g_free (priv->name);
|
||||
priv->name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_PROPERTIES:
|
||||
if (priv->properties)
|
||||
g_variant_unref (priv->properties);
|
||||
priv->properties = g_value_dup_variant (value);
|
||||
break;
|
||||
|
||||
case PROP_SUBSCRIPTION_MASK:
|
||||
priv->subscription_mask = g_value_get_flags (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_context_class_init (PvContextClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvContextPrivate));
|
||||
|
||||
gobject_class->set_property = pv_context_set_property;
|
||||
gobject_class->get_property = pv_context_get_property;
|
||||
|
||||
/**
|
||||
* PvContext:name
|
||||
*
|
||||
* The application name of the context.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NAME,
|
||||
g_param_spec_string ("name",
|
||||
"Name",
|
||||
"The application name",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:properties
|
||||
*
|
||||
* Properties of the context.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PROPERTIES,
|
||||
g_param_spec_variant ("properties",
|
||||
"Properties",
|
||||
"Extra properties",
|
||||
G_VARIANT_TYPE_VARIANT,
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:state
|
||||
*
|
||||
* The state of the context.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_STATE,
|
||||
g_param_spec_enum ("state",
|
||||
"State",
|
||||
"The context state",
|
||||
PV_TYPE_CONTEXT_STATE,
|
||||
PV_CONTEXT_STATE_UNCONNECTED,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:subscription-mask
|
||||
*
|
||||
* A mask for what object notifications will be signaled with
|
||||
* PvContext:subscription-event
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SUBSCRIPTION_MASK,
|
||||
g_param_spec_flags ("subscription-mask",
|
||||
"Subscription Mask",
|
||||
"The object to receive subscription events of",
|
||||
PV_TYPE_SUBSCRIPTION_FLAGS,
|
||||
0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:connection
|
||||
*
|
||||
* The connection of the context.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CONNECTION,
|
||||
g_param_spec_object ("connection",
|
||||
"Connection",
|
||||
"The DBus connection",
|
||||
G_TYPE_DBUS_CONNECTION,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:client-path
|
||||
*
|
||||
* The client object path of the context.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CLIENT_PATH,
|
||||
g_param_spec_string ("client-path",
|
||||
"Client Path",
|
||||
"The client object path",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvContext:subscription-event
|
||||
* @context: The #PvContext emitting the signal.
|
||||
* @event: A #PvSubscriptionEvent
|
||||
* @flags: #PvSubscriptionFlags indicating the object
|
||||
* @path: the object path
|
||||
*
|
||||
* Notify about a new object that was added/removed/modified.
|
||||
*/
|
||||
signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_generic,
|
||||
G_TYPE_NONE,
|
||||
3,
|
||||
PV_TYPE_SUBSCRIPTION_EVENT,
|
||||
PV_TYPE_SUBSCRIPTION_FLAGS,
|
||||
G_TYPE_STRING);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_context_init (PvContext * context)
|
||||
{
|
||||
PvContextPrivate *priv = context->priv = PV_CONTEXT_GET_PRIVATE (context);
|
||||
|
||||
priv->state = PV_CONTEXT_STATE_UNCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_context_new:
|
||||
* @name: an application name
|
||||
* @properties: optional properties
|
||||
*
|
||||
* Make a new unconnected #PvContext
|
||||
*
|
||||
* Returns: a new unconnected #PvContext
|
||||
*/
|
||||
PvContext *
|
||||
pv_context_new (const gchar *name, GVariant *properties)
|
||||
{
|
||||
return g_object_new (PV_TYPE_CONTEXT, "name", name, "properties", properties, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
context_set_state (PvContext *context, PvContextState state)
|
||||
{
|
||||
if (context->priv->state != state) {
|
||||
context->priv->state = state;
|
||||
g_object_notify (G_OBJECT (context), "state");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_context_get_state:
|
||||
* @context: a #PvContext
|
||||
*
|
||||
* Get the state of @context.
|
||||
*
|
||||
* Returns: the state of @context
|
||||
*/
|
||||
PvContextState
|
||||
pv_context_get_state (PvContext *context)
|
||||
{
|
||||
PvContextPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_CONTEXT (context), PV_CONTEXT_STATE_ERROR);
|
||||
priv = context->priv;
|
||||
|
||||
return priv->state;
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_proxy (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->client = pv_client1_proxy_new_finish (res, &error);
|
||||
if (priv->client == NULL) {
|
||||
context_set_state (context, PV_CONTEXT_STATE_ERROR);
|
||||
g_error ("failed to get client proxy: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
context_set_state (context, PV_CONTEXT_STATE_READY);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_connected (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!pv_daemon1_call_connect_client_finish (priv->daemon, &priv->client_path, res, &error)) {
|
||||
context_set_state (context, PV_CONTEXT_STATE_ERROR);
|
||||
g_error ("failed to connect client: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
pv_client1_proxy_new (priv->connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
PV_DBUS_SERVICE,
|
||||
priv->client_path,
|
||||
NULL,
|
||||
on_client_proxy,
|
||||
context);
|
||||
}
|
||||
|
||||
static void
|
||||
on_daemon_connected (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->daemon = pv_daemon1_proxy_new_finish (res, &error);
|
||||
if (priv->daemon == NULL) {
|
||||
context_set_state (context, PV_CONTEXT_STATE_ERROR);
|
||||
g_error ("failed to get daemon: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
context_set_state (context, PV_CONTEXT_STATE_REGISTERING);
|
||||
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
|
||||
|
||||
pv_daemon1_call_connect_client (priv->daemon,
|
||||
g_variant_builder_end (&builder), /* GVariant *arg_properties */
|
||||
NULL, /* GCancellable *cancellable */
|
||||
on_client_connected,
|
||||
context);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_name_appeared (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
priv->connection = connection;
|
||||
|
||||
install_subscription (context);
|
||||
|
||||
pv_daemon1_proxy_new (priv->connection,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
name,
|
||||
PV_DBUS_OBJECT_SERVER,
|
||||
NULL,
|
||||
on_daemon_connected,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_vanished (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
uninstall_subscription (context);
|
||||
|
||||
priv->connection = connection;
|
||||
|
||||
if (priv->flags & PV_CONTEXT_FLAGS_NOFAIL) {
|
||||
context_set_state (context, PV_CONTEXT_STATE_CONNECTING);
|
||||
} else {
|
||||
context_set_state (context, PV_CONTEXT_STATE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_context_connect:
|
||||
* @context: a #PvContext
|
||||
* @flags: #PvContextFlags
|
||||
*
|
||||
* Connect to the daemon with @flags
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pv_context_connect (PvContext *context, PvContextFlags flags)
|
||||
{
|
||||
PvContextPrivate *priv;
|
||||
GBusNameWatcherFlags nw_flags;
|
||||
|
||||
g_return_val_if_fail (PV_IS_CONTEXT (context), FALSE);
|
||||
|
||||
priv = context->priv;
|
||||
g_return_val_if_fail (priv->connection == NULL, FALSE);
|
||||
|
||||
priv->flags = flags;
|
||||
|
||||
context_set_state (context, PV_CONTEXT_STATE_CONNECTING);
|
||||
|
||||
nw_flags = G_BUS_NAME_WATCHER_FLAGS_NONE;
|
||||
if (!(flags & PV_CONTEXT_FLAGS_NOAUTOSPAWN))
|
||||
nw_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START;
|
||||
|
||||
priv->id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
PV_DBUS_SERVICE,
|
||||
nw_flags,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
context,
|
||||
NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_context_get_connection:
|
||||
* @context: a #PvContext
|
||||
*
|
||||
* Get the #GDBusConnection of @context.
|
||||
*
|
||||
* Returns: the #GDBusConnection of @context or %NULL when not connected.
|
||||
*/
|
||||
GDBusConnection *
|
||||
pv_context_get_connection (PvContext *context)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_CONTEXT (context), NULL);
|
||||
|
||||
return context->priv->connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_context_get_client_path:
|
||||
* @context: a #PvContext
|
||||
*
|
||||
* Get the client object path that @context is registered with
|
||||
*
|
||||
* Returns: the client object path of @context or %NULL when not
|
||||
* registered.
|
||||
*/
|
||||
const gchar *
|
||||
pv_context_get_client_path (PvContext *context)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_CONTEXT (context), NULL);
|
||||
|
||||
return context->priv->client_path;
|
||||
}
|
||||
|
||||
110
src/client/pv-context.h
Normal file
110
src/client/pv-context.h
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_CONTEXT_H__
|
||||
#define __PV_CONTEXT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_CONTEXT (pv_context_get_type ())
|
||||
#define PV_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_CONTEXT))
|
||||
#define PV_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_CONTEXT))
|
||||
#define PV_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_CONTEXT, PvContextClass))
|
||||
#define PV_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_CONTEXT, PvContext))
|
||||
#define PV_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_CONTEXT, PvContextClass))
|
||||
#define PV_CONTEXT_CAST(obj) ((PvContext*)(obj))
|
||||
#define PV_CONTEXT_CLASS_CAST(klass) ((PvContextClass*)(klass))
|
||||
|
||||
typedef struct _PvContext PvContext;
|
||||
typedef struct _PvContextClass PvContextClass;
|
||||
typedef struct _PvContextPrivate PvContextPrivate;
|
||||
|
||||
/**
|
||||
* PvContextFlags:
|
||||
* @PV_CONTEXT_FLAGS_NONE: no flags
|
||||
* @PV_CONTEXT_FLAGS_NOAUTOSPAWN: disable autostart of the daemon
|
||||
* @PV_CONTEXT_FLAGS_NOFAIL: Don't fail if the daemon is not available,
|
||||
* instead enter PV_CONTEXT_CONNECTING state and wait for the daemon
|
||||
* to appear.
|
||||
*
|
||||
* Context flags passed to pv_context_connect()
|
||||
*/
|
||||
typedef enum {
|
||||
PV_CONTEXT_FLAGS_NONE = 0,
|
||||
PV_CONTEXT_FLAGS_NOAUTOSPAWN = (1 << 0),
|
||||
PV_CONTEXT_FLAGS_NOFAIL = (1 << 1)
|
||||
} PvContextFlags;
|
||||
|
||||
/**
|
||||
* PvContextState:
|
||||
* @PV_CONTEXT_STATE_UNCONNECTED: not connected
|
||||
* @PV_CONTEXT_STATE_CONNECTING: connecting to daemon
|
||||
* @PV_CONTEXT_STATE_REGISTERING: registering with daemon
|
||||
* @PV_CONTEXT_STATE_READY: context is ready
|
||||
* @PV_CONTEXT_STATE_ERROR: context is in error
|
||||
*
|
||||
* The state of a #PvContext
|
||||
*/
|
||||
typedef enum {
|
||||
PV_CONTEXT_STATE_UNCONNECTED = 0,
|
||||
PV_CONTEXT_STATE_CONNECTING = 1,
|
||||
PV_CONTEXT_STATE_REGISTERING = 2,
|
||||
PV_CONTEXT_STATE_READY = 3,
|
||||
PV_CONTEXT_STATE_ERROR = 4
|
||||
} PvContextState;
|
||||
|
||||
/**
|
||||
* PvContext:
|
||||
*
|
||||
* Pulsevideo context object class.
|
||||
*/
|
||||
struct _PvContext {
|
||||
GObject object;
|
||||
|
||||
PvContextPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvContextClass:
|
||||
*
|
||||
* Pulsevideo context object class.
|
||||
*/
|
||||
struct _PvContextClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_context_get_type (void);
|
||||
|
||||
PvContext * pv_context_new (const gchar *name, GVariant *properties);
|
||||
|
||||
gboolean pv_context_connect (PvContext *context, PvContextFlags flags);
|
||||
|
||||
GDBusConnection * pv_context_get_connection (PvContext *context);
|
||||
const gchar * pv_context_get_client_path (PvContext *context);
|
||||
|
||||
PvContextState pv_context_get_state (PvContext *context);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_CONTEXT_H__ */
|
||||
|
||||
731
src/client/pv-stream.c
Normal file
731
src/client/pv-stream.c
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gio/gunixfdlist.h>
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
#include "client/pv-context.h"
|
||||
#include "client/pv-stream.h"
|
||||
#include "client/pv-enumtypes.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
struct _PvStreamPrivate
|
||||
{
|
||||
PvContext *context;
|
||||
gchar *name;
|
||||
gchar *target;
|
||||
PvStreamState state;
|
||||
|
||||
PvCapture1 *capture;
|
||||
gchar *source_output_path;
|
||||
PvSourceOutput1 *source_output;
|
||||
|
||||
GSocket *socket;
|
||||
PvStreamMode mode;
|
||||
guint socket_id;
|
||||
|
||||
PvBufferInfo info;
|
||||
};
|
||||
|
||||
#define PV_STREAM_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_STREAM, PvStreamPrivate))
|
||||
|
||||
G_DEFINE_TYPE (PvStream, pv_stream, G_TYPE_OBJECT);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_CONTEXT,
|
||||
PROP_NAME,
|
||||
PROP_STATE,
|
||||
PROP_SOCKET
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_NEW_BUFFER,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
pv_stream_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvStream *stream = PV_STREAM (_object);
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CONTEXT:
|
||||
g_value_set_object (value, priv->context);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, priv->name);
|
||||
break;
|
||||
|
||||
case PROP_STATE:
|
||||
g_value_set_enum (value, priv->state);
|
||||
break;
|
||||
|
||||
case PROP_SOCKET:
|
||||
g_value_set_object (value, priv->socket);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (stream, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_stream_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvStream *stream = PV_STREAM (_object);
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_CONTEXT:
|
||||
priv->context = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
priv->name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (stream, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_stream_finalize (GObject * object)
|
||||
{
|
||||
PvStream *stream = PV_STREAM (object);
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
g_free (priv->name);
|
||||
|
||||
G_OBJECT_CLASS (pv_stream_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_stream_class_init (PvStreamClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvStreamPrivate));
|
||||
|
||||
gobject_class->finalize = pv_stream_finalize;
|
||||
gobject_class->set_property = pv_stream_set_property;
|
||||
gobject_class->get_property = pv_stream_get_property;
|
||||
|
||||
/**
|
||||
* PvStream:context
|
||||
*
|
||||
* The context of the stream.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_CONTEXT,
|
||||
g_param_spec_object ("context",
|
||||
"Context",
|
||||
"The context",
|
||||
PV_TYPE_CONTEXT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvStream:name
|
||||
*
|
||||
* The name of the stream as specified at construction time.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NAME,
|
||||
g_param_spec_string ("name",
|
||||
"Name",
|
||||
"The name of the stream",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
/**
|
||||
* PvStream:state
|
||||
*
|
||||
* The state of the stream. Use the notify::state signal to be notified
|
||||
* of state changes.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_STATE,
|
||||
g_param_spec_enum ("state",
|
||||
"State",
|
||||
"The stream state",
|
||||
PV_TYPE_STREAM_STATE,
|
||||
PV_STREAM_STATE_UNCONNECTED,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* PvStream:socket
|
||||
*
|
||||
* The socket of the stream. When doing pv_stream_start() with
|
||||
* #PV_STREAM_MODE_SOCKET, the socket will contain a data stream with
|
||||
* meta data and anciliary data containing fds with the data.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SOCKET,
|
||||
g_param_spec_object ("socket",
|
||||
"Socket",
|
||||
"The stream socket",
|
||||
G_TYPE_SOCKET,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
|
||||
/**
|
||||
* PvStream:new-buffer
|
||||
*
|
||||
* When doing pv_stream_start() with #PV_STREAM_MODE_BUFFER, this signal
|
||||
* will be fired whenever a new buffer can be obtained with
|
||||
* pv_stream_capture_buffer().
|
||||
*/
|
||||
signals[SIGNAL_NEW_BUFFER] = g_signal_new ("new-buffer",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_generic,
|
||||
G_TYPE_NONE,
|
||||
0,
|
||||
G_TYPE_NONE);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_stream_init (PvStream * stream)
|
||||
{
|
||||
PvStreamPrivate *priv = stream->priv = PV_STREAM_GET_PRIVATE (stream);
|
||||
|
||||
priv->state = PV_STREAM_STATE_UNCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_new:
|
||||
* @context: a #PvContext
|
||||
* @name: a stream name
|
||||
*
|
||||
* Make a new unconnected #PvStream
|
||||
*
|
||||
* Returns: a new unconnected #PvStream
|
||||
*/
|
||||
PvStream *
|
||||
pv_stream_new (PvContext * context, const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_CONTEXT (context), NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
return g_object_new (PV_TYPE_STREAM, "context", context, "name", name, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
stream_set_state (PvStream *stream, PvStreamState state)
|
||||
{
|
||||
if (stream->priv->state != state) {
|
||||
stream->priv->state = state;
|
||||
g_object_notify (G_OBJECT (stream), "state");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_get_state:
|
||||
* @stream: a #PvStream
|
||||
*
|
||||
* Get the state of @stream.
|
||||
*
|
||||
* Returns: the state of @stream
|
||||
*/
|
||||
PvStreamState
|
||||
pv_stream_get_state (PvStream *stream)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), PV_STREAM_STATE_ERROR);
|
||||
|
||||
return stream->priv->state;
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_output1_proxy (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->source_output = pv_source_output1_proxy_new_finish (res, &error);
|
||||
if (priv->source_output == NULL) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to get source output proxy: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
stream_set_state (stream, PV_STREAM_STATE_READY);
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_output_created (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
PvContext *context = priv->context;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!pv_capture1_call_create_source_output_finish (priv->capture,
|
||||
&priv->source_output_path, res, &error)) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_print ("failed to get connect capture: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
pv_source_output1_proxy_new (pv_context_get_connection (context),
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
PV_DBUS_SERVICE,
|
||||
priv->source_output_path,
|
||||
NULL,
|
||||
on_source_output1_proxy,
|
||||
stream);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
create_source_output (PvStream *stream)
|
||||
{
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
|
||||
|
||||
pv_capture1_call_create_source_output (priv->capture,
|
||||
priv->target ? priv->target : "/", /* const gchar *arg_source */
|
||||
g_variant_builder_end (&builder), /* GVariant *arg_props */
|
||||
NULL, /* GCancellable *cancellable */
|
||||
on_source_output_created,
|
||||
stream);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_output_removed (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!pv_capture1_call_remove_source_output_finish (priv->capture,
|
||||
res, &error)) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_print ("failed to disconnect: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
g_clear_pointer (&priv->source_output_path, g_free);
|
||||
g_clear_object (&priv->source_output);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
remove_source_output (PvStream *stream)
|
||||
{
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
pv_capture1_call_remove_source_output (priv->capture,
|
||||
priv->source_output_path,
|
||||
NULL, /* GCancellable *cancellable */
|
||||
on_source_output_removed,
|
||||
stream);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_capture_proxy (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->capture = pv_capture1_proxy_new_finish (res, &error);
|
||||
if (priv->capture == NULL) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to get capture proxy: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
create_source_output (stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pv_stream_connect_capture:
|
||||
* @stream: a #PvStream
|
||||
* @device: the device name to connect to
|
||||
* @flags: a #PvStreamFlags
|
||||
*
|
||||
* Connect @stream for capturing from @device.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pv_stream_connect_capture (PvStream *stream,
|
||||
const gchar *source,
|
||||
PvStreamFlags flags)
|
||||
{
|
||||
PvStreamPrivate *priv;
|
||||
PvContext *context;
|
||||
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
|
||||
priv = stream->priv;
|
||||
context = priv->context;
|
||||
g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE);
|
||||
|
||||
priv->target = g_strdup (source);
|
||||
|
||||
stream_set_state (stream, PV_STREAM_STATE_CONNECTING);
|
||||
|
||||
if (priv->capture == NULL) {
|
||||
pv_capture1_proxy_new (pv_context_get_connection (context),
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
PV_DBUS_SERVICE,
|
||||
pv_context_get_client_path (context),
|
||||
NULL,
|
||||
on_capture_proxy,
|
||||
stream);
|
||||
|
||||
return TRUE;
|
||||
} else {
|
||||
return create_source_output (stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_disconnect:
|
||||
* @stream: a #PvStream
|
||||
*
|
||||
* Disconnect @stream.
|
||||
*
|
||||
* Returns: %TRUE on success
|
||||
*/
|
||||
gboolean
|
||||
pv_stream_disconnect (PvStream *stream)
|
||||
{
|
||||
PvStreamPrivate *priv;
|
||||
PvContext *context;
|
||||
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
|
||||
priv = stream->priv;
|
||||
g_return_val_if_fail (priv->state >= PV_STREAM_STATE_READY, FALSE);
|
||||
g_return_val_if_fail (priv->capture != NULL, FALSE);
|
||||
context = priv->context;
|
||||
g_return_val_if_fail (pv_context_get_state (context) == PV_CONTEXT_STATE_READY, FALSE);
|
||||
|
||||
remove_source_output (stream);
|
||||
|
||||
stream_set_state (stream, PV_STREAM_STATE_UNCONNECTED);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
guint64 offset;
|
||||
guint64 size;
|
||||
} FDMessage;
|
||||
|
||||
static gboolean
|
||||
on_socket_data (GSocket *socket,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
switch (condition) {
|
||||
case G_IO_IN:
|
||||
{
|
||||
gssize len;
|
||||
GInputVector ivec;
|
||||
FDMessage msg;
|
||||
GSocketControlMessage **messages = NULL;
|
||||
gint num_messages = 0;
|
||||
gint flags = 0;
|
||||
GError *error = NULL;
|
||||
|
||||
ivec.buffer = &msg;
|
||||
ivec.size = sizeof (msg);
|
||||
|
||||
len = g_socket_receive_message (socket,
|
||||
NULL,
|
||||
&ivec,
|
||||
1,
|
||||
&messages,
|
||||
&num_messages,
|
||||
&flags,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
g_assert (len == sizeof (msg));
|
||||
|
||||
if (priv->info.message)
|
||||
g_object_unref (priv->info.message);
|
||||
priv->info.offset = msg.offset;
|
||||
priv->info.size = msg.size;
|
||||
priv->info.message = num_messages > 0 ? messages[0] : NULL;
|
||||
|
||||
g_signal_emit (stream, SIGNAL_NEW_BUFFER, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_socket (PvStream *stream, gint fd)
|
||||
{
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
g_print ("got fd %d\n", fd);
|
||||
priv->socket = g_socket_new_from_fd (fd, &error);
|
||||
if (priv->socket == NULL) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to create socket: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (priv->mode) {
|
||||
case PV_STREAM_MODE_SOCKET:
|
||||
g_object_notify (G_OBJECT (stream), "socket");
|
||||
break;
|
||||
|
||||
case PV_STREAM_MODE_BUFFER:
|
||||
{
|
||||
GSource *source;
|
||||
|
||||
source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
|
||||
g_source_set_callback (source, (GSourceFunc) on_socket_data, stream, NULL);
|
||||
priv->socket_id = g_source_attach (source, NULL);
|
||||
g_source_unref (source);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unhandle_socket (PvStream *stream)
|
||||
{
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
|
||||
switch (priv->mode) {
|
||||
case PV_STREAM_MODE_SOCKET:
|
||||
g_clear_object (&priv->socket);
|
||||
g_object_notify (G_OBJECT (stream), "socket");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_stream_acquired (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GUnixFDList *out_fd_list;
|
||||
gint fd_idx, fd;
|
||||
GVariant *out_props;
|
||||
GError *error = NULL;
|
||||
GVariant *result;
|
||||
|
||||
result = g_dbus_proxy_call_with_unix_fd_list_finish (G_DBUS_PROXY (priv->source_output), &out_fd_list, res, &error);
|
||||
if (result == NULL) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to acquire: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (result,
|
||||
"(h@a{sv})",
|
||||
&fd_idx,
|
||||
&out_props);
|
||||
|
||||
g_variant_unref (result);
|
||||
g_variant_unref (out_props);
|
||||
|
||||
if ((fd = g_unix_fd_list_get (out_fd_list, fd_idx, &error)) < 0) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to get FD: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
handle_socket (stream, fd);
|
||||
|
||||
stream_set_state (stream, PV_STREAM_STATE_STREAMING);
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_start:
|
||||
* @stream: a #PvStream
|
||||
* @mode: a #PvStreamMode
|
||||
*
|
||||
* Start capturing from @stream.
|
||||
*
|
||||
* When @mode is #PV_STREAM_MODE_SOCKET, you should connect to the notify::socket
|
||||
* signal to obtain a readable socket with metadata and data.
|
||||
*
|
||||
* When @mode is ##PV_STREAM_MODE_BUFFER, you should connect to the new-buffer
|
||||
* signal and use pv_stream_capture_buffer() to get the latest metadata and
|
||||
* data.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pv_stream_start (PvStream *stream, PvStreamMode mode)
|
||||
{
|
||||
PvStreamPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
|
||||
|
||||
priv = stream->priv;
|
||||
g_return_val_if_fail (priv->state == PV_STREAM_STATE_READY, FALSE);
|
||||
|
||||
priv->mode = mode;
|
||||
|
||||
stream_set_state (stream, PV_STREAM_STATE_STARTING);
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string ("hello"));
|
||||
|
||||
pv_source_output1_call_acquire (priv->source_output,
|
||||
g_variant_builder_end (&builder), /* GVariant *arg_properties */
|
||||
NULL, /* GCancellable *cancellable */
|
||||
on_stream_acquired,
|
||||
stream);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_stream_released (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStream *stream = user_data;
|
||||
PvStreamPrivate *priv = stream->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!pv_source_output1_call_release_finish (priv->source_output,
|
||||
res, &error)) {
|
||||
stream_set_state (stream, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to release: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
unhandle_socket (stream);
|
||||
|
||||
stream_set_state (stream, PV_STREAM_STATE_READY);
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_stop:
|
||||
* @stream: a #PvStream
|
||||
*
|
||||
* Stop capturing from @stream.
|
||||
*
|
||||
* Returns: %TRUE on success.
|
||||
*/
|
||||
gboolean
|
||||
pv_stream_stop (PvStream *stream)
|
||||
{
|
||||
PvStreamPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
|
||||
|
||||
priv = stream->priv;
|
||||
g_return_val_if_fail (priv->state == PV_STREAM_STATE_STREAMING, FALSE);
|
||||
|
||||
pv_source_output1_call_release (priv->source_output,
|
||||
NULL, /* GCancellable *cancellable */
|
||||
on_stream_released,
|
||||
stream);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* pv_stream_capture_buffer:
|
||||
* @stream: a #PvStream
|
||||
* @info: a #PvBufferInfo
|
||||
*
|
||||
* Capture the next buffer from @stream. This function should be called every
|
||||
* time after the new-buffer callback has been emitted.
|
||||
*
|
||||
* Returns: %TRUE when @info contains valid information
|
||||
*/
|
||||
gboolean
|
||||
pv_stream_capture_buffer (PvStream *stream, PvBufferInfo *info)
|
||||
{
|
||||
PvStreamPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_STREAM (stream), FALSE);
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
priv = stream->priv;
|
||||
g_return_val_if_fail (priv->state == PV_STREAM_STATE_STREAMING, FALSE);
|
||||
|
||||
*info = priv->info;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
113
src/client/pv-stream.h
Normal file
113
src/client/pv-stream.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_STREAM_H__
|
||||
#define __PV_STREAM_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "pv-context.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_STREAM (pv_stream_get_type ())
|
||||
#define PV_IS_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_STREAM))
|
||||
#define PV_IS_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_STREAM))
|
||||
#define PV_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_STREAM, PvStreamClass))
|
||||
#define PV_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_STREAM, PvStream))
|
||||
#define PV_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_STREAM, PvStreamClass))
|
||||
#define PV_STREAM_CAST(obj) ((PvStream*)(obj))
|
||||
#define PV_STREAM_CLASS_CAST(klass) ((PvStreamClass*)(klass))
|
||||
|
||||
typedef struct _PvStream PvStream;
|
||||
typedef struct _PvStreamClass PvStreamClass;
|
||||
typedef struct _PvStreamPrivate PvStreamPrivate;
|
||||
|
||||
typedef enum {
|
||||
PV_STREAM_STATE_UNCONNECTED = 0,
|
||||
PV_STREAM_STATE_CONNECTING = 1,
|
||||
PV_STREAM_STATE_READY = 2,
|
||||
PV_STREAM_STATE_STARTING = 3,
|
||||
PV_STREAM_STATE_STREAMING = 4,
|
||||
PV_STREAM_STATE_ERROR = 5
|
||||
} PvStreamState;
|
||||
|
||||
|
||||
typedef enum {
|
||||
PV_STREAM_FLAGS_NONE = 0,
|
||||
} PvStreamFlags;
|
||||
|
||||
typedef struct {
|
||||
gint64 timestamp;
|
||||
guint64 seq;
|
||||
guint64 offset;
|
||||
guint64 size;
|
||||
GSocketControlMessage *message;
|
||||
} PvBufferInfo;
|
||||
|
||||
typedef enum {
|
||||
PV_STREAM_MODE_SOCKET = 0,
|
||||
PV_STREAM_MODE_BUFFER = 1,
|
||||
} PvStreamMode;
|
||||
|
||||
/**
|
||||
* PvStream:
|
||||
*
|
||||
* Pulsevideo stream object class.
|
||||
*/
|
||||
struct _PvStream {
|
||||
GObject object;
|
||||
|
||||
PvStreamPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvStreamClass:
|
||||
*
|
||||
* Pulsevideo stream object class.
|
||||
*/
|
||||
struct _PvStreamClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_stream_get_type (void);
|
||||
|
||||
|
||||
PvStream * pv_stream_new (PvContext * context,
|
||||
const gchar *name);
|
||||
|
||||
PvStreamState pv_stream_get_state (PvStream *stream);
|
||||
|
||||
gboolean pv_stream_connect_capture (PvStream *stream,
|
||||
const gchar *source,
|
||||
PvStreamFlags flags);
|
||||
gboolean pv_stream_disconnect (PvStream *stream);
|
||||
|
||||
gboolean pv_stream_start (PvStream *stream, PvStreamMode mode);
|
||||
gboolean pv_stream_stop (PvStream *stream);
|
||||
|
||||
gboolean pv_stream_capture_buffer (PvStream *stream,
|
||||
PvBufferInfo *info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_STREAM_H__ */
|
||||
|
||||
183
src/client/pv-subscribe.c
Normal file
183
src/client/pv-subscribe.c
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/* Pulsevideo
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static void
|
||||
notify_subscription (PvContext *context,
|
||||
GDBusObject *object,
|
||||
GDBusInterface *interface,
|
||||
PvSubscriptionEvent event)
|
||||
{
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_CLIENT) {
|
||||
if ((interface == NULL && pv_object_peek_client1 (PV_OBJECT (object))) ||
|
||||
PV_IS_CLIENT1_PROXY (interface))
|
||||
g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
|
||||
PV_SUBSCRIPTION_FLAGS_CLIENT, g_dbus_object_get_object_path (object));
|
||||
}
|
||||
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_DEVICE) {
|
||||
if ((interface == NULL && pv_object_peek_device1 (PV_OBJECT (object))) ||
|
||||
PV_IS_DEVICE1_PROXY (interface))
|
||||
g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
|
||||
PV_SUBSCRIPTION_FLAGS_DEVICE, g_dbus_object_get_object_path (object));
|
||||
}
|
||||
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE) {
|
||||
if ((interface == NULL && pv_object_peek_source1 (PV_OBJECT (object))) ||
|
||||
PV_IS_SOURCE1_PROXY (interface))
|
||||
g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
|
||||
PV_SUBSCRIPTION_FLAGS_SOURCE, g_dbus_object_get_object_path (object));
|
||||
}
|
||||
if (priv->subscription_mask & PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT) {
|
||||
if ((interface == NULL && pv_object_peek_source_output1 (PV_OBJECT (object))) ||
|
||||
PV_IS_SOURCE_OUTPUT1_PROXY (interface))
|
||||
g_signal_emit (context, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, event,
|
||||
PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT, g_dbus_object_get_object_path (object));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_interface_added (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
GDBusInterface *interface,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_NEW);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_interface_removed (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
GDBusInterface *interface,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
notify_subscription (context, object, interface, PV_SUBSCRIPTION_EVENT_REMOVE);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_object_added (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_NEW);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_object_removed (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
notify_subscription (context, object, NULL, PV_SUBSCRIPTION_EVENT_REMOVE);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_properties_changed (GDBusObjectManagerClient *manager,
|
||||
GDBusObjectProxy *object_proxy,
|
||||
GDBusProxy *interface_proxy,
|
||||
GVariant *changed_properties,
|
||||
GStrv invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("properties changed\n");
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_signal (GDBusObjectManagerClient *manager,
|
||||
GDBusObjectProxy *object_proxy,
|
||||
GDBusProxy *interface_proxy,
|
||||
gchar *sender_name,
|
||||
gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("proxy signal %s\n", signal_name);
|
||||
}
|
||||
|
||||
static void
|
||||
connect_client_signals (PvContext *context)
|
||||
{
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
g_signal_connect (priv->client_manager, "interface-added",
|
||||
(GCallback) on_client_manager_interface_added, context);
|
||||
g_signal_connect (priv->client_manager, "interface-removed",
|
||||
(GCallback) on_client_manager_interface_removed, context);
|
||||
g_signal_connect (priv->client_manager, "object-added",
|
||||
(GCallback) on_client_manager_object_added, context);
|
||||
g_signal_connect (priv->client_manager, "object-removed",
|
||||
(GCallback) on_client_manager_object_removed, context);
|
||||
g_signal_connect (priv->client_manager, "interface-proxy-signal",
|
||||
(GCallback) on_client_manager_signal, context);
|
||||
g_signal_connect (priv->client_manager, "interface-proxy-properties-changed",
|
||||
(GCallback) on_client_manager_properties_changed, context);
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_manager_ready (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->client_manager = pv_object_manager_client_new_finish (res, &error);
|
||||
if (priv->client_manager == NULL)
|
||||
goto manager_error;
|
||||
|
||||
connect_client_signals (context);
|
||||
|
||||
return;
|
||||
|
||||
/* ERRORS */
|
||||
manager_error:
|
||||
{
|
||||
g_warning ("could not create client manager: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
install_subscription (PvContext *context)
|
||||
{
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
if (priv->client_manager)
|
||||
return;
|
||||
|
||||
pv_object_manager_client_new (pv_context_get_connection (context),
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
PV_DBUS_SERVICE,
|
||||
PV_DBUS_OBJECT_PREFIX,
|
||||
NULL,
|
||||
on_client_manager_ready,
|
||||
context);
|
||||
}
|
||||
|
||||
static void
|
||||
uninstall_subscription (PvContext *context)
|
||||
{
|
||||
PvContextPrivate *priv = context->priv;
|
||||
|
||||
g_clear_object (&priv->client_manager);
|
||||
}
|
||||
45
src/client/pv-subscribe.h
Normal file
45
src/client/pv-subscribe.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_SUBSCRIBE_H__
|
||||
#define __PV_SUBSCRIBE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
PV_SUBSCRIPTION_FLAGS_CLIENT = (1 << 0),
|
||||
PV_SUBSCRIPTION_FLAGS_DEVICE = (1 << 1),
|
||||
PV_SUBSCRIPTION_FLAGS_SOURCE = (1 << 2),
|
||||
PV_SUBSCRIPTION_FLAGS_SOURCE_OUTPUT = (1 << 3),
|
||||
|
||||
PV_SUBSCRIPTION_FLAGS_ALL = 0xf
|
||||
} PvSubscriptionFlags;
|
||||
|
||||
typedef enum {
|
||||
PV_SUBSCRIPTION_EVENT_NEW = 0,
|
||||
PV_SUBSCRIPTION_EVENT_CHANGE = 1,
|
||||
PV_SUBSCRIPTION_EVENT_REMOVE = 2,
|
||||
} PvSubscriptionEvent;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_SUBSCRIBE_H__ */
|
||||
|
||||
44
src/daemon/main.c
Normal file
44
src/daemon/main.c
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gio/gio.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
PvDaemon *daemon;
|
||||
GMainLoop *loop;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
daemon = pv_daemon_new ();
|
||||
pv_daemon_start (daemon);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_main_loop_unref (loop);
|
||||
g_object_unref (daemon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
src/daemon/pulsevideo-system.conf
Normal file
31
src/daemon/pulsevideo-system.conf
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0"?><!--*-nxml-*-->
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of PulseVideo.
|
||||
|
||||
PulseVideo is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
PulseVideo 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 Lesser General
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with PulseVideo; if not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<busconfig>
|
||||
|
||||
<!-- System-wide PulseVideo runs as 'pulsevideo' user. This fragment is
|
||||
not necessary for user PulseVideo instances. -->
|
||||
|
||||
<policy user="pulsevideo">
|
||||
<allow own="org.pulsevideo"/>
|
||||
</policy>
|
||||
|
||||
</busconfig>
|
||||
2
src/dbus/.gitignore
vendored
Normal file
2
src/dbus/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
org-pulsevideo.c
|
||||
org-pulsevideo.h
|
||||
95
src/dbus/org.pulsevideo.xml
Normal file
95
src/dbus/org.pulsevideo.xml
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<node>
|
||||
<interface name='org.pulsevideo.Daemon1'>
|
||||
<property name='UserName' type='s' access='read' />
|
||||
<property name='HostName' type='s' access='read' />
|
||||
<property name='Version' type='s' access='read' />
|
||||
<property name='Name' type='s' access='read' />
|
||||
<property name='Properties' type='a{sv}' access='read' />
|
||||
<method name='ConnectClient'>
|
||||
<arg type='a{sv}' name='properties' direction='in'/>
|
||||
<arg type='o' name='client' direction='out'/>
|
||||
</method>
|
||||
<method name='DisconnectClient'>
|
||||
<arg type='o' name='client' direction='in'/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Client1'>
|
||||
<property name='Name' type='s' access='read' />
|
||||
<property name='Properties' type='a{sv}' access='read' />
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Capture1'>
|
||||
<method name='CreateSourceOutput'>
|
||||
<arg type='o' name='source' direction='in'/>
|
||||
<arg type='a{sv}' name='props' direction='in'/>
|
||||
<arg type='o' name='output' direction='out'/>
|
||||
</method>
|
||||
<method name='RemoveSourceOutput'>
|
||||
<arg type='o' name='output' direction='in'/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Manager1'>
|
||||
<method name='AddProvider'>
|
||||
<arg type='o' name='provider' direction='in'/>
|
||||
<arg type='a{sv}' name='properties' direction='in'/>
|
||||
</method>
|
||||
<method name='RemoveProvider'>
|
||||
<arg type='o' name='provider' direction='in'/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Introspect1'>
|
||||
<method name='GetClients'>
|
||||
<arg type='ao' name='clients' direction='out'/>
|
||||
</method>
|
||||
<method name='GetProviders'>
|
||||
<arg type='ao' name='providers' direction='out'/>
|
||||
</method>
|
||||
<method name='GetSources'>
|
||||
<arg type='ao' name='sources' direction='out'/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Device1'>
|
||||
<property name='Name' type='s' access='read' />
|
||||
<property name='Properties' type='a{sv}' access='read' />
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.Source1'>
|
||||
<property name='Name' type='s' access='read' />
|
||||
<property name='Suspended' type='b' access='read' />
|
||||
<property name='Properties' type='a{sv}' access='read' />
|
||||
<method name='GetCapabilities'>
|
||||
<arg type='a{sv}' name='props' direction='in'/>
|
||||
<arg type='aa{sv}' name='caps' direction='out'/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
<interface name='org.pulsevideo.SourceOutput1'>
|
||||
<method name='Acquire'>
|
||||
<arg type='a{sv}' name='props' direction='in'/>
|
||||
<arg type='h' name='fd' direction='out'/>
|
||||
<arg type='a{sv}' name='props' direction='out'/>
|
||||
</method>
|
||||
<method name='Release'>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
<method name='Start'>
|
||||
<arg type='a{sv}' name='props' direction='in'/>
|
||||
<arg type='a{sv}' name='props' direction='out'/>
|
||||
</method>
|
||||
<method name='Stop'>
|
||||
</method>
|
||||
<signal name='NewData'>
|
||||
<arg type='h' name='data' direction='out'/>
|
||||
<arg type='a{sv}' name='props' direction='out'/>
|
||||
</signal>
|
||||
<method name='FreeData'>
|
||||
<arg type='h' name='data' direction='in'/>
|
||||
</method>
|
||||
-->
|
||||
</interface>
|
||||
</node>
|
||||
130
src/modules/v4l2/pv-v4l2-source.c
Normal file
130
src/modules/v4l2/pv-v4l2-source.c
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gst/gst.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pv-v4l2-source.h"
|
||||
|
||||
#define PV_V4L2_SOURCE_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2SourcePrivate))
|
||||
|
||||
struct _PvV4l2SourcePrivate
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *sink;
|
||||
|
||||
GSocket *socket;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PvV4l2Source, pv_v4l2_source, PV_TYPE_SOURCE);
|
||||
|
||||
static void
|
||||
setup_pipeline (PvV4l2Source *source)
|
||||
{
|
||||
PvV4l2SourcePrivate *priv = source->priv;
|
||||
|
||||
priv->pipeline = gst_parse_launch ("v4l2src ! video/x-raw,width=320,height=240,framerate=30/1 ! "
|
||||
"pvfdpay ! multisocketsink buffers-max=2 buffers-soft-max=1 "
|
||||
"recover-policy=latest sync-method=latest name=sink sync=true "
|
||||
"enable-last-sample=false", NULL);
|
||||
priv->sink = gst_bin_get_by_name (GST_BIN (priv->pipeline), "sink");
|
||||
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_READY);
|
||||
}
|
||||
|
||||
static void
|
||||
on_socket_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvV4l2Source *source = user_data;
|
||||
PvV4l2SourcePrivate *priv = source->priv;
|
||||
GSocket *socket;
|
||||
guint num_handles;
|
||||
|
||||
g_object_get (gobject, "socket", &socket, NULL);
|
||||
|
||||
if (socket == NULL) {
|
||||
if (priv->socket)
|
||||
g_signal_emit_by_name (priv->sink, "remove", priv->socket);
|
||||
} else {
|
||||
g_signal_emit_by_name (priv->sink, "add", socket);
|
||||
}
|
||||
priv->socket = socket;
|
||||
|
||||
g_object_get (priv->sink, "num-handles", &num_handles, NULL);
|
||||
if (num_handles == 0) {
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_READY);
|
||||
} else {
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
static PvSourceOutput *
|
||||
v4l2_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
|
||||
{
|
||||
PvSourceOutput *output;
|
||||
|
||||
output = PV_SOURCE_CLASS (pv_v4l2_source_parent_class)->create_source_output (source, props, prefix);
|
||||
|
||||
g_signal_connect (output, "notify::socket", (GCallback) on_socket_notify, source);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
v4l2_release_source_output (PvSource *source, PvSourceOutput *output)
|
||||
{
|
||||
return PV_SOURCE_CLASS (pv_v4l2_source_parent_class)->release_source_output (source, output);
|
||||
}
|
||||
|
||||
static void
|
||||
v4l2_source_finalize (GObject * object)
|
||||
{
|
||||
G_OBJECT_CLASS (pv_v4l2_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_v4l2_source_class_init (PvV4l2SourceClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
PvSourceClass *source_class = PV_SOURCE_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvV4l2SourcePrivate));
|
||||
|
||||
gobject_class->finalize = v4l2_source_finalize;
|
||||
|
||||
source_class->create_source_output = v4l2_create_source_output;
|
||||
source_class->release_source_output = v4l2_release_source_output;
|
||||
}
|
||||
|
||||
static void
|
||||
pv_v4l2_source_init (PvV4l2Source * source)
|
||||
{
|
||||
source->priv = PV_V4L2_SOURCE_GET_PRIVATE (source);
|
||||
|
||||
setup_pipeline (source);
|
||||
}
|
||||
|
||||
PvSource *
|
||||
pv_v4l2_source_new (PvDaemon *daemon)
|
||||
{
|
||||
return g_object_new (PV_TYPE_V4L2_SOURCE, "daemon", daemon, NULL);
|
||||
}
|
||||
58
src/modules/v4l2/pv-v4l2-source.h
Normal file
58
src/modules/v4l2/pv-v4l2-source.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_V4L2_SOURCE_H__
|
||||
#define __PV_V4L2_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "server/pv-source.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_V4L2_SOURCE (pv_v4l2_source_get_type ())
|
||||
#define PV_IS_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_V4L2_SOURCE))
|
||||
#define PV_IS_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_V4L2_SOURCE))
|
||||
#define PV_V4L2_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2SourceClass))
|
||||
#define PV_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2Source))
|
||||
#define PV_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_V4L2_SOURCE, PvV4l2SourceClass))
|
||||
#define PV_V4L2_SOURCE_CAST(obj) ((PvV4l2Source*)(obj))
|
||||
#define PV_V4L2_SOURCE_CLASS_CAST(klass) ((PvV4l2SourceClass*)(klass))
|
||||
|
||||
typedef struct _PvV4l2Source PvV4l2Source;
|
||||
typedef struct _PvV4l2SourceClass PvV4l2SourceClass;
|
||||
typedef struct _PvV4l2SourcePrivate PvV4l2SourcePrivate;
|
||||
|
||||
struct _PvV4l2Source {
|
||||
PvSource object;
|
||||
|
||||
PvV4l2SourcePrivate *priv;
|
||||
};
|
||||
|
||||
struct _PvV4l2SourceClass {
|
||||
PvSourceClass parent_class;
|
||||
};
|
||||
|
||||
GType pv_v4l2_source_get_type (void);
|
||||
|
||||
PvSource * pv_v4l2_source_new (PvDaemon *daemon);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_V4L2_SOURCE_H__ */
|
||||
|
||||
279
src/server/pv-client.c
Normal file
279
src/server/pv-client.c
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/* Pulsevideo
|
||||
* 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 "server/pv-client.h"
|
||||
#include "server/pv-source.h"
|
||||
#include "server/pv-source-output.h"
|
||||
#include "client/pv-enumtypes.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
struct _PvClientPrivate
|
||||
{
|
||||
PvDaemon *daemon;
|
||||
gchar *object_path;
|
||||
|
||||
PvSource *source;
|
||||
|
||||
GHashTable *source_outputs;
|
||||
};
|
||||
|
||||
#define PV_CLIENT_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_CLIENT, PvClientPrivate))
|
||||
|
||||
G_DEFINE_TYPE (PvClient, pv_client, G_TYPE_OBJECT);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON,
|
||||
PROP_OBJECT_PATH,
|
||||
};
|
||||
|
||||
static void
|
||||
pv_client_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvClient *client = PV_CLIENT (_object);
|
||||
PvClientPrivate *priv = client->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, priv->daemon);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_PATH:
|
||||
g_value_set_string (value, priv->object_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_client_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvClient *client = PV_CLIENT (_object);
|
||||
PvClientPrivate *priv = client->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
priv->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_PATH:
|
||||
priv->object_path = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (client, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_create_source_output (PvCapture1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_source,
|
||||
GVariant *arg_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvClient *client = user_data;
|
||||
PvClientPrivate *priv = client->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
PvSource *source;
|
||||
PvSourceOutput *output;
|
||||
const gchar *object_path;
|
||||
|
||||
source = pv_daemon_get_source (daemon, arg_source);
|
||||
|
||||
output = pv_source_create_source_output (source, NULL, priv->object_path);
|
||||
|
||||
object_path = pv_source_output_get_object_path (output);
|
||||
g_hash_table_insert (priv->source_outputs, g_strdup (object_path), output);
|
||||
pv_capture1_complete_create_source_output (interface, invocation, object_path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_source_output (PvCapture1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_output,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvClient *client = user_data;
|
||||
PvClientPrivate *priv = client->priv;
|
||||
PvSourceOutput *output;
|
||||
|
||||
output = g_hash_table_lookup (priv->source_outputs, arg_output);
|
||||
if (output) {
|
||||
pv_source_release_source_output (priv->source, output);
|
||||
g_hash_table_remove (priv->source_outputs, arg_output);
|
||||
}
|
||||
|
||||
pv_capture1_complete_remove_source_output (interface, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
client_register_object (PvClient *client, const gchar *prefix)
|
||||
{
|
||||
PvClientPrivate *priv = client->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
GDBusObjectSkeleton *skel;
|
||||
gchar *name;
|
||||
|
||||
name = g_strdup_printf ("%s/client", prefix);
|
||||
skel = g_dbus_object_skeleton_new (name);
|
||||
g_free (name);
|
||||
|
||||
{
|
||||
PvClient1 *iface;
|
||||
|
||||
iface = pv_client1_skeleton_new ();
|
||||
pv_client1_set_name (iface, "poppy");
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
{
|
||||
PvCapture1 *iface;
|
||||
|
||||
iface = pv_capture1_skeleton_new ();
|
||||
g_signal_connect (iface, "handle-create-source-output", (GCallback) handle_create_source_output, client);
|
||||
g_signal_connect (iface, "handle-remove-source-output", (GCallback) handle_remove_source_output, client);
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
|
||||
g_free (priv->object_path);
|
||||
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
|
||||
}
|
||||
|
||||
static void
|
||||
client_unregister_object (PvClient *client)
|
||||
{
|
||||
PvClientPrivate *priv = client->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
|
||||
g_hash_table_unref (priv->source_outputs);
|
||||
g_clear_object (&priv->source);
|
||||
|
||||
pv_daemon_unexport (daemon, priv->object_path);
|
||||
g_free (priv->object_path);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_client_finalize (GObject * object)
|
||||
{
|
||||
PvClient *client = PV_CLIENT (object);
|
||||
|
||||
client_unregister_object (client);
|
||||
|
||||
G_OBJECT_CLASS (pv_client_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_client_constructed (GObject * object)
|
||||
{
|
||||
PvClient *client = PV_CLIENT (object);
|
||||
PvClientPrivate *priv = client->priv;
|
||||
|
||||
client_register_object (client, priv->object_path);
|
||||
|
||||
G_OBJECT_CLASS (pv_client_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_client_class_init (PvClientClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvClientPrivate));
|
||||
|
||||
gobject_class->finalize = pv_client_finalize;
|
||||
gobject_class->set_property = pv_client_set_property;
|
||||
gobject_class->get_property = pv_client_get_property;
|
||||
gobject_class->constructed = pv_client_constructed;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The daemon",
|
||||
PV_TYPE_DAEMON,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT_PATH,
|
||||
g_param_spec_string ("object-path",
|
||||
"Object Path",
|
||||
"The object path",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
pv_client_init (PvClient * client)
|
||||
{
|
||||
PvClientPrivate *priv = client->priv = PV_CLIENT_GET_PRIVATE (client);
|
||||
|
||||
priv->source_outputs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pv_client_new:
|
||||
*
|
||||
* Make a new unconnected #PvClient
|
||||
*
|
||||
* Returns: a new unconnected #PvClient
|
||||
*/
|
||||
PvClient *
|
||||
pv_client_new (PvDaemon * daemon, const gchar *prefix)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
|
||||
g_return_val_if_fail (g_variant_is_object_path (prefix), NULL);
|
||||
|
||||
return g_object_new (PV_TYPE_CLIENT, "daemon", daemon, "object-path", prefix, NULL);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pv_client_get_object_path (PvClient *client)
|
||||
{
|
||||
PvClientPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_CLIENT (client), NULL);
|
||||
priv = client->priv;
|
||||
|
||||
return priv->object_path;
|
||||
}
|
||||
|
||||
72
src/server/pv-client.h
Normal file
72
src/server/pv-client.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_CLIENT_H__
|
||||
#define __PV_CLIENT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "pv-daemon.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_CLIENT (pv_client_get_type ())
|
||||
#define PV_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_CLIENT))
|
||||
#define PV_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_CLIENT))
|
||||
#define PV_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_CLIENT, PvClientClass))
|
||||
#define PV_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_CLIENT, PvClient))
|
||||
#define PV_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_CLIENT, PvClientClass))
|
||||
#define PV_CLIENT_CAST(obj) ((PvClient*)(obj))
|
||||
#define PV_CLIENT_CLASS_CAST(klass) ((PvClientClass*)(klass))
|
||||
|
||||
typedef struct _PvClient PvClient;
|
||||
typedef struct _PvClientClass PvClientClass;
|
||||
typedef struct _PvClientPrivate PvClientPrivate;
|
||||
|
||||
/**
|
||||
* PvClient:
|
||||
*
|
||||
* Pulsevideo client object class.
|
||||
*/
|
||||
struct _PvClient {
|
||||
GObject object;
|
||||
|
||||
PvClientPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvClientClass:
|
||||
*
|
||||
* Pulsevideo client object class.
|
||||
*/
|
||||
struct _PvClientClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_client_get_type (void);
|
||||
|
||||
PvClient * pv_client_new (PvDaemon *daemon, const gchar *prefix);
|
||||
|
||||
const gchar * pv_client_get_object_path (PvClient *client);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_CLIENT_H__ */
|
||||
|
||||
354
src/server/pv-daemon.c
Normal file
354
src/server/pv-daemon.c
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gio/gio.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
#include "server/pv-client.h"
|
||||
#include "modules/v4l2/pv-v4l2-source.h"
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
#define PV_DAEMON_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_DAEMON, PvDaemonPrivate))
|
||||
|
||||
struct _PvDaemonPrivate
|
||||
{
|
||||
guint id;
|
||||
GDBusConnection *connection;
|
||||
GDBusObjectManagerServer *server_manager;
|
||||
|
||||
GHashTable *senders;
|
||||
PvSource *source;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PvDaemon *daemon;
|
||||
gchar *sender;
|
||||
guint id;
|
||||
|
||||
GHashTable *clients;
|
||||
} SenderData;
|
||||
|
||||
static void
|
||||
client_name_appeared_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
const gchar *name_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
client_name_vanished_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
SenderData *data = user_data;
|
||||
PvDaemonPrivate *priv = data->daemon->priv;
|
||||
|
||||
g_print ("vanished client %s\n", name);
|
||||
|
||||
g_hash_table_unref (data->clients);
|
||||
g_hash_table_remove (priv->senders, data->sender);
|
||||
g_free (data->sender);
|
||||
g_bus_unwatch_name (data->id);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static SenderData *
|
||||
sender_data_new (PvDaemon *daemon, const gchar *sender)
|
||||
{
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
SenderData *data;
|
||||
|
||||
data = g_new0 (SenderData, 1);
|
||||
data->daemon = daemon;
|
||||
data->sender = g_strdup (sender);
|
||||
data->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
|
||||
data->id = g_bus_watch_name_on_connection (priv->connection,
|
||||
sender,
|
||||
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||
client_name_appeared_handler,
|
||||
client_name_vanished_handler,
|
||||
data,
|
||||
NULL);
|
||||
|
||||
g_hash_table_insert (priv->senders, data->sender, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_connect_client (PvDaemon1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
PvClient *client;
|
||||
const gchar *sender, *object_path;
|
||||
SenderData *data;
|
||||
|
||||
sender = g_dbus_method_invocation_get_sender (invocation);
|
||||
|
||||
g_print ("connect client %s\n", sender);
|
||||
data = g_hash_table_lookup (priv->senders, sender);
|
||||
if (data == NULL) {
|
||||
data = sender_data_new (daemon, sender);
|
||||
}
|
||||
|
||||
client = pv_client_new (daemon, PV_DBUS_OBJECT_PREFIX);
|
||||
object_path = pv_client_get_object_path (client);
|
||||
|
||||
g_hash_table_insert (data->clients, g_strdup (object_path), client);
|
||||
|
||||
pv_daemon1_complete_connect_client (interface, invocation, object_path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_disconnect_client (PvDaemon1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_client,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
const gchar *sender;
|
||||
SenderData *data;
|
||||
|
||||
sender = g_dbus_method_invocation_get_sender (invocation);
|
||||
|
||||
g_print ("disconnect client %s\n", sender);
|
||||
data = g_hash_table_lookup (priv->senders, sender);
|
||||
if (data != NULL) {
|
||||
g_hash_table_remove (data->clients, arg_client);
|
||||
}
|
||||
|
||||
pv_daemon1_complete_disconnect_client (interface, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_add_provider (PvManager1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_provider,
|
||||
GVariant *arg_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("add provider\n");
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.pulseaudio.Error.NotImplemented",
|
||||
"Operation add not yet implemented");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_remove_provider (PvManager1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *arg_provider,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("remove provider\n");
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.pulseaudio.Error.NotImplemented",
|
||||
"Operation remove not yet implemented");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
export_server_object (PvDaemon *daemon, GDBusObjectManagerServer *manager)
|
||||
{
|
||||
GDBusObjectSkeleton *skel;
|
||||
|
||||
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SERVER);
|
||||
{
|
||||
PvDaemon1 *iface;
|
||||
|
||||
iface = pv_daemon1_skeleton_new ();
|
||||
g_signal_connect (iface, "handle-connect-client", (GCallback) handle_connect_client, daemon);
|
||||
g_signal_connect (iface, "handle-disconnect-client", (GCallback) handle_disconnect_client, daemon);
|
||||
pv_daemon1_set_user_name (iface, g_get_user_name ());
|
||||
pv_daemon1_set_host_name (iface, g_get_host_name ());
|
||||
pv_daemon1_set_version (iface, PACKAGE_VERSION);
|
||||
pv_daemon1_set_name (iface, PACKAGE_NAME);
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
{
|
||||
PvManager1 *iface;
|
||||
|
||||
iface = pv_manager1_skeleton_new ();
|
||||
g_signal_connect (iface, "handle-add-provider", (GCallback) handle_add_provider, daemon);
|
||||
g_signal_connect (iface, "handle-remove-provider", (GCallback) handle_remove_provider, daemon);
|
||||
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
g_dbus_object_manager_server_export (manager, skel);
|
||||
g_object_unref (skel);
|
||||
}
|
||||
|
||||
static void
|
||||
bus_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
|
||||
priv->connection = connection;
|
||||
}
|
||||
|
||||
static void
|
||||
name_acquired_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
GDBusObjectManagerServer *manager;
|
||||
|
||||
priv->server_manager = manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX);
|
||||
export_server_object (daemon, manager);
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
name_lost_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
GDBusObjectManagerServer *manager = priv->server_manager;
|
||||
|
||||
g_dbus_object_manager_server_unexport (manager, PV_DBUS_OBJECT_SERVER);
|
||||
g_clear_object (&priv->server_manager);
|
||||
}
|
||||
|
||||
PvDaemon *
|
||||
pv_daemon_new (void)
|
||||
{
|
||||
return g_object_new (PV_TYPE_DAEMON, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pv_daemon_start (PvDaemon *daemon)
|
||||
{
|
||||
PvDaemonPrivate *priv;
|
||||
|
||||
g_return_if_fail (PV_IS_DAEMON (daemon));
|
||||
|
||||
priv = daemon->priv;
|
||||
g_return_if_fail (priv->id == 0);
|
||||
|
||||
priv->id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
PV_DBUS_SERVICE,
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE,
|
||||
bus_acquired_handler,
|
||||
name_acquired_handler,
|
||||
name_lost_handler,
|
||||
daemon,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pv_daemon_stop (PvDaemon *daemon)
|
||||
{
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
|
||||
g_return_if_fail (PV_IS_DAEMON (daemon));
|
||||
|
||||
g_bus_unown_name (priv->id);
|
||||
priv->id = 0;
|
||||
}
|
||||
|
||||
gchar *
|
||||
pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel)
|
||||
{
|
||||
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
|
||||
g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (skel), NULL);
|
||||
|
||||
g_dbus_object_manager_server_export_uniquely (daemon->priv->server_manager, skel);
|
||||
|
||||
return g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (skel)));
|
||||
}
|
||||
|
||||
void
|
||||
pv_daemon_unexport (PvDaemon *daemon, const gchar *object_path)
|
||||
{
|
||||
g_return_if_fail (PV_IS_DAEMON (daemon));
|
||||
g_return_if_fail (g_variant_is_object_path (object_path));
|
||||
|
||||
g_dbus_object_manager_server_unexport (daemon->priv->server_manager, object_path);
|
||||
}
|
||||
|
||||
PvSource *
|
||||
pv_daemon_get_source (PvDaemon *daemon, const gchar *name)
|
||||
{
|
||||
PvDaemonPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_DAEMON (daemon), NULL);
|
||||
priv = daemon->priv;
|
||||
|
||||
if (priv->source == NULL) {
|
||||
priv->source = pv_v4l2_source_new (daemon);
|
||||
}
|
||||
return priv->source;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (PvDaemon, pv_daemon, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
pv_daemon_finalize (GObject * object)
|
||||
{
|
||||
PvDaemon *daemon = PV_DAEMON_CAST (object);
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
|
||||
g_hash_table_unref (priv->senders);
|
||||
pv_daemon_stop (daemon);
|
||||
|
||||
G_OBJECT_CLASS (pv_daemon_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_daemon_class_init (PvDaemonClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvDaemonPrivate));
|
||||
|
||||
gobject_class->finalize = pv_daemon_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
pv_daemon_init (PvDaemon * daemon)
|
||||
{
|
||||
PvDaemonPrivate *priv = daemon->priv = PV_DAEMON_GET_PRIVATE (daemon);
|
||||
|
||||
priv->senders = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
85
src/server/pv-daemon.h
Normal file
85
src/server/pv-daemon.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_DAEMON_H__
|
||||
#define __PV_DAEMON_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_DAEMON (pv_daemon_get_type ())
|
||||
#define PV_IS_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_DAEMON))
|
||||
#define PV_IS_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_DAEMON))
|
||||
#define PV_DAEMON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_DAEMON, PvDaemonClass))
|
||||
#define PV_DAEMON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_DAEMON, PvDaemon))
|
||||
#define PV_DAEMON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_DAEMON, PvDaemonClass))
|
||||
#define PV_DAEMON_CAST(obj) ((PvDaemon*)(obj))
|
||||
#define PV_DAEMON_CLASS_CAST(klass) ((PvDaemonClass*)(klass))
|
||||
|
||||
typedef struct _PvDaemon PvDaemon;
|
||||
typedef struct _PvDaemonClass PvDaemonClass;
|
||||
typedef struct _PvDaemonPrivate PvDaemonPrivate;
|
||||
|
||||
#include "server/pv-source.h"
|
||||
|
||||
#define PV_DBUS_SERVICE "org.pulsevideo"
|
||||
#define PV_DBUS_OBJECT_PREFIX "/org/pulsevideo"
|
||||
#define PV_DBUS_OBJECT_SERVER PV_DBUS_OBJECT_PREFIX "/server"
|
||||
#define PV_DBUS_OBJECT_SOURCE PV_DBUS_OBJECT_PREFIX "/source"
|
||||
#define PV_DBUS_OBJECT_CLIENT PV_DBUS_OBJECT_PREFIX "/client"
|
||||
|
||||
/**
|
||||
* PvDaemon:
|
||||
*
|
||||
* Pulsevideo daemon object class.
|
||||
*/
|
||||
struct _PvDaemon {
|
||||
GObject object;
|
||||
|
||||
PvDaemonPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvDaemonClass:
|
||||
*
|
||||
* Pulsevideo daemon object class.
|
||||
*/
|
||||
struct _PvDaemonClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_daemon_get_type (void);
|
||||
|
||||
PvDaemon * pv_daemon_new (void);
|
||||
|
||||
void pv_daemon_start (PvDaemon *daemon);
|
||||
void pv_daemon_stop (PvDaemon *daemon);
|
||||
|
||||
gchar * pv_daemon_export_uniquely (PvDaemon *daemon, GDBusObjectSkeleton *skel);
|
||||
void pv_daemon_unexport (PvDaemon *daemon, const gchar *name);
|
||||
|
||||
PvSource * pv_daemon_get_source (PvDaemon *daemon, const gchar *name);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_DAEMON_H__ */
|
||||
|
||||
273
src/server/pv-source-output.c
Normal file
273
src/server/pv-source-output.c
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/* Pulsevideo
|
||||
* 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 <sys/socket.h>
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
#include "server/pv-source-output.h"
|
||||
#include "client/pv-enumtypes.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
struct _PvSourceOutputPrivate
|
||||
{
|
||||
PvDaemon *daemon;
|
||||
gchar *object_path;
|
||||
GSocket *socket;
|
||||
};
|
||||
|
||||
#define PV_SOURCE_OUTPUT_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputPrivate))
|
||||
|
||||
G_DEFINE_TYPE (PvSourceOutput, pv_source_output, G_TYPE_OBJECT);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON,
|
||||
PROP_OBJECT_PATH,
|
||||
PROP_SOCKET,
|
||||
};
|
||||
|
||||
static void
|
||||
pv_source_output_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvSourceOutput *output = PV_SOURCE_OUTPUT (_object);
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, priv->daemon);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_PATH:
|
||||
g_value_set_string (value, priv->object_path);
|
||||
break;
|
||||
|
||||
case PROP_SOCKET:
|
||||
g_value_set_object (value, priv->socket);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_output_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvSourceOutput *output = PV_SOURCE_OUTPUT (_object);
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
priv->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_PATH:
|
||||
priv->object_path = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (output, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_acquire (PvSourceOutput1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *arg_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvSourceOutput *output = user_data;
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
GUnixFDList *fdlist;
|
||||
GVariantBuilder props;
|
||||
gint fd[2];
|
||||
|
||||
g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&props, "{sv}", "name", g_variant_new_string ("hello"));
|
||||
|
||||
socketpair (AF_UNIX, SOCK_STREAM, 0, fd);
|
||||
priv->socket = g_socket_new_from_fd (fd[0], NULL);
|
||||
g_object_notify (G_OBJECT (output), "socket");
|
||||
|
||||
fdlist = g_unix_fd_list_new ();
|
||||
g_unix_fd_list_append (fdlist, fd[1], NULL);
|
||||
g_dbus_method_invocation_return_value_with_unix_fd_list (invocation,
|
||||
g_variant_new ("(h@a{sv})", 0, g_variant_builder_end (&props)),
|
||||
fdlist);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
stop_transfer (PvSourceOutput *output)
|
||||
{
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
|
||||
if (priv->socket) {
|
||||
g_clear_object (&priv->socket);
|
||||
g_object_notify (G_OBJECT (output), "socket");
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_release (PvSourceOutput1 *interface,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvSourceOutput *output = user_data;
|
||||
|
||||
stop_transfer (output);
|
||||
|
||||
pv_source_output1_complete_release (interface, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
output_register_object (PvSourceOutput *output, const gchar *prefix)
|
||||
{
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
GDBusObjectSkeleton *skel;
|
||||
gchar *name;
|
||||
|
||||
name = g_strdup_printf ("%s/output", prefix);
|
||||
skel = g_dbus_object_skeleton_new (name);
|
||||
g_free (name);
|
||||
|
||||
{
|
||||
PvSourceOutput1 *iface;
|
||||
|
||||
iface = pv_source_output1_skeleton_new ();
|
||||
g_signal_connect (iface, "handle-acquire", (GCallback) handle_acquire, output);
|
||||
g_signal_connect (iface, "handle-release", (GCallback) handle_release, output);
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
|
||||
g_free (priv->object_path);
|
||||
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
|
||||
}
|
||||
|
||||
static void
|
||||
output_unregister_object (PvSourceOutput *output)
|
||||
{
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
|
||||
stop_transfer (output);
|
||||
|
||||
pv_daemon_unexport (daemon, priv->object_path);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_output_finalize (GObject * object)
|
||||
{
|
||||
PvSourceOutput *output = PV_SOURCE_OUTPUT (object);
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
|
||||
output_unregister_object (output);
|
||||
g_object_unref (priv->daemon);
|
||||
g_free (priv->object_path);
|
||||
|
||||
G_OBJECT_CLASS (pv_source_output_parent_class)->finalize (object);
|
||||
}
|
||||
static void
|
||||
pv_source_output_constructed (GObject * object)
|
||||
{
|
||||
PvSourceOutput *output = PV_SOURCE_OUTPUT (object);
|
||||
PvSourceOutputPrivate *priv = output->priv;
|
||||
|
||||
output_register_object (output, priv->object_path);
|
||||
|
||||
G_OBJECT_CLASS (pv_source_output_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_output_class_init (PvSourceOutputClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvSourceOutputPrivate));
|
||||
|
||||
gobject_class->finalize = pv_source_output_finalize;
|
||||
gobject_class->set_property = pv_source_output_set_property;
|
||||
gobject_class->get_property = pv_source_output_get_property;
|
||||
gobject_class->constructed = pv_source_output_constructed;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The daemon",
|
||||
PV_TYPE_DAEMON,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT_PATH,
|
||||
g_param_spec_string ("object-path",
|
||||
"Object Path",
|
||||
"The object path",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SOCKET,
|
||||
g_param_spec_object ("socket",
|
||||
"Socket",
|
||||
"The socket with data",
|
||||
G_TYPE_SOCKET,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_output_init (PvSourceOutput * output)
|
||||
{
|
||||
output->priv = PV_SOURCE_OUTPUT_GET_PRIVATE (output);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pv_source_output_get_object_path (PvSourceOutput *output)
|
||||
{
|
||||
PvSourceOutputPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE_OUTPUT (output), NULL);
|
||||
priv = output->priv;
|
||||
|
||||
return priv->object_path;
|
||||
}
|
||||
|
||||
68
src/server/pv-source-output.h
Normal file
68
src/server/pv-source-output.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_SOURCE_OUTPUT_H__
|
||||
#define __PV_SOURCE_OUTPUT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_SOURCE_OUTPUT (pv_source_output_get_type ())
|
||||
#define PV_IS_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE_OUTPUT))
|
||||
#define PV_IS_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SOURCE_OUTPUT))
|
||||
#define PV_SOURCE_OUTPUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputClass))
|
||||
#define PV_SOURCE_OUTPUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SOURCE_OUTPUT, PvSourceOutput))
|
||||
#define PV_SOURCE_OUTPUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SOURCE_OUTPUT, PvSourceOutputClass))
|
||||
#define PV_SOURCE_OUTPUT_CAST(obj) ((PvSourceOutput*)(obj))
|
||||
#define PV_SOURCE_OUTPUT_CLASS_CAST(klass) ((PvSourceOutputClass*)(klass))
|
||||
|
||||
typedef struct _PvSourceOutput PvSourceOutput;
|
||||
typedef struct _PvSourceOutputClass PvSourceOutputClass;
|
||||
typedef struct _PvSourceOutputPrivate PvSourceOutputPrivate;
|
||||
|
||||
/**
|
||||
* PvSourceOutput:
|
||||
*
|
||||
* Pulsevideo source output object class.
|
||||
*/
|
||||
struct _PvSourceOutput {
|
||||
GObject object;
|
||||
|
||||
PvSourceOutputPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvSourceOutputClass:
|
||||
*
|
||||
* Pulsevideo source output object class.
|
||||
*/
|
||||
struct _PvSourceOutputClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_source_output_get_type (void);
|
||||
|
||||
const gchar * pv_source_output_get_object_path (PvSourceOutput *output);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_SOURCE_OUTPUT_H__ */
|
||||
|
||||
288
src/server/pv-source.c
Normal file
288
src/server/pv-source.c
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gio/gio.h>
|
||||
|
||||
#include "server/pv-source.h"
|
||||
#include "server/pv-daemon.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
|
||||
#define PV_SOURCE_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_SOURCE, PvSourcePrivate))
|
||||
|
||||
struct _PvSourcePrivate
|
||||
{
|
||||
PvDaemon *daemon;
|
||||
gchar *object_path;
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (PvSource, pv_source, G_TYPE_OBJECT);
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON,
|
||||
PROP_OBJECT_PATH
|
||||
};
|
||||
|
||||
static void
|
||||
pv_source_get_property (GObject *_object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvSource *source = PV_SOURCE (_object);
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, priv->daemon);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_PATH:
|
||||
g_value_set_string (value, priv->object_path);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_set_property (GObject *_object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvSource *source = PV_SOURCE (_object);
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
priv->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (source, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
source_register_object (PvSource *source)
|
||||
{
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
GDBusObjectSkeleton *skel;
|
||||
|
||||
skel = g_dbus_object_skeleton_new (PV_DBUS_OBJECT_SOURCE);
|
||||
{
|
||||
PvSource1 *iface;
|
||||
|
||||
iface = pv_source1_skeleton_new ();
|
||||
g_dbus_object_skeleton_add_interface (skel, G_DBUS_INTERFACE_SKELETON (iface));
|
||||
g_object_unref (iface);
|
||||
}
|
||||
g_free (priv->object_path);
|
||||
priv->object_path = pv_daemon_export_uniquely (daemon, skel);
|
||||
}
|
||||
|
||||
static void
|
||||
source_unregister_object (PvSource *source)
|
||||
{
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
PvDaemon *daemon = priv->daemon;
|
||||
|
||||
pv_daemon_unexport (daemon, priv->object_path);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_finalize (GObject * object)
|
||||
{
|
||||
PvSource *source = PV_SOURCE (object);
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
|
||||
source_unregister_object (source);
|
||||
g_object_unref (priv->daemon);
|
||||
g_free (priv->object_path);
|
||||
|
||||
G_OBJECT_CLASS (pv_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_constructed (GObject * object)
|
||||
{
|
||||
PvSource *source = PV_SOURCE (object);
|
||||
|
||||
source_register_object (source);
|
||||
|
||||
G_OBJECT_CLASS (pv_source_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static PvSourceOutput *
|
||||
default_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
|
||||
{
|
||||
PvSourcePrivate *priv = source->priv;
|
||||
|
||||
return g_object_new (PV_TYPE_SOURCE_OUTPUT, "daemon", priv->daemon, "object-path", prefix, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
default_release_source_output (PvSource *source, PvSourceOutput *output)
|
||||
{
|
||||
g_object_unref (output);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pv_source_class_init (PvSourceClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvSourcePrivate));
|
||||
|
||||
gobject_class->finalize = pv_source_finalize;
|
||||
gobject_class->set_property = pv_source_set_property;
|
||||
gobject_class->get_property = pv_source_get_property;
|
||||
gobject_class->constructed = pv_source_constructed;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The daemon",
|
||||
PV_TYPE_DAEMON,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_OBJECT_PATH,
|
||||
g_param_spec_string ("object-path",
|
||||
"Object Path",
|
||||
"The object path",
|
||||
NULL,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
klass->create_source_output = default_create_source_output;
|
||||
klass->release_source_output = default_release_source_output;
|
||||
}
|
||||
|
||||
static void
|
||||
pv_source_init (PvSource * source)
|
||||
{
|
||||
source->priv = PV_SOURCE_GET_PRIVATE (source);
|
||||
}
|
||||
|
||||
GVariant *
|
||||
pv_source_get_capabilities (PvSource *source, GVariant *props)
|
||||
{
|
||||
PvSourceClass *klass;
|
||||
GVariant *res;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE (source), NULL);
|
||||
|
||||
klass = PV_SOURCE_GET_CLASS (source);
|
||||
|
||||
if (klass->get_capabilities)
|
||||
res = klass->get_capabilities (source, props);
|
||||
else
|
||||
res = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pv_source_suspend (PvSource *source)
|
||||
{
|
||||
PvSourceClass *klass;
|
||||
gboolean res;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
|
||||
|
||||
klass = PV_SOURCE_GET_CLASS (source);
|
||||
|
||||
if (klass->suspend)
|
||||
res = klass->suspend (source);
|
||||
else
|
||||
res = FALSE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pv_source_resume (PvSource *source)
|
||||
{
|
||||
PvSourceClass *klass;
|
||||
gboolean res;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
|
||||
|
||||
klass = PV_SOURCE_GET_CLASS (source);
|
||||
|
||||
if (klass->resume)
|
||||
res = klass->resume (source);
|
||||
else
|
||||
res = FALSE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
PvSourceOutput *
|
||||
pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix)
|
||||
{
|
||||
PvSourceClass *klass;
|
||||
PvSourceOutput *res;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE (source), NULL);
|
||||
|
||||
klass = PV_SOURCE_GET_CLASS (source);
|
||||
|
||||
if (klass->create_source_output)
|
||||
res = klass->create_source_output (source, props, prefix);
|
||||
else
|
||||
res = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pv_source_release_source_output (PvSource *source, PvSourceOutput *output)
|
||||
{
|
||||
PvSourceClass *klass;
|
||||
gboolean res;
|
||||
|
||||
g_return_val_if_fail (PV_IS_SOURCE (source), FALSE);
|
||||
g_return_val_if_fail (PV_IS_SOURCE_OUTPUT (output), FALSE);
|
||||
|
||||
klass = PV_SOURCE_GET_CLASS (source);
|
||||
|
||||
if (klass->release_source_output)
|
||||
res = klass->release_source_output (source, output);
|
||||
else
|
||||
res = FALSE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
87
src/server/pv-source.h
Normal file
87
src/server/pv-source.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* Pulsevideo
|
||||
* 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 __PV_SOURCE_H__
|
||||
#define __PV_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _PvSource PvSource;
|
||||
typedef struct _PvSourceClass PvSourceClass;
|
||||
typedef struct _PvSourcePrivate PvSourcePrivate;
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
#include "server/pv-source-output.h"
|
||||
|
||||
#define PV_TYPE_SOURCE (pv_source_get_type ())
|
||||
#define PV_IS_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_SOURCE))
|
||||
#define PV_IS_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_SOURCE))
|
||||
#define PV_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_SOURCE, PvSourceClass))
|
||||
#define PV_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_SOURCE, PvSource))
|
||||
#define PV_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_SOURCE, PvSourceClass))
|
||||
#define PV_SOURCE_CAST(obj) ((PvSource*)(obj))
|
||||
#define PV_SOURCE_CLASS_CAST(klass) ((PvSourceClass*)(klass))
|
||||
|
||||
/**
|
||||
* PvSource:
|
||||
*
|
||||
* Pulsevideo source object class.
|
||||
*/
|
||||
struct _PvSource {
|
||||
GObject object;
|
||||
|
||||
PvSourcePrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* PvSourceClass:
|
||||
*
|
||||
* Pulsevideo source object class.
|
||||
*/
|
||||
struct _PvSourceClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
GVariant * (*get_capabilities) (PvSource *source, GVariant *props);
|
||||
|
||||
gboolean (*suspend) (PvSource *source);
|
||||
gboolean (*resume) (PvSource *source);
|
||||
|
||||
PvSourceOutput * (*create_source_output) (PvSource *source, GVariant *props, const gchar *prefix);
|
||||
gboolean (*release_source_output) (PvSource *source, PvSourceOutput *output);
|
||||
};
|
||||
|
||||
/* normal GObject stuff */
|
||||
GType pv_source_get_type (void);
|
||||
|
||||
PvSource * pv_source_new (PvDaemon *daemon, const gchar *prefix);
|
||||
|
||||
GVariant * pv_source_get_capabilities (PvSource *source, GVariant *props);
|
||||
|
||||
gboolean pv_source_suspend (PvSource *source);
|
||||
gboolean pv_source_resume (PvSource *source);
|
||||
|
||||
PvSourceOutput * pv_source_create_source_output (PvSource *source, GVariant *props, const gchar *prefix);
|
||||
gboolean pv_source_release_source_output (PvSource *source, PvSourceOutput *output);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_SOURCE_H__ */
|
||||
|
||||
128
src/tests/test-client.c
Normal file
128
src/tests/test-client.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gst/gst.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <client/pv-context.h>
|
||||
#include <client/pv-stream.h>
|
||||
|
||||
#define CAPS "video/x-raw, format=(string)YUY2, width=(int)320, height=(int)240, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive, framerate=(fraction)30/1"
|
||||
|
||||
static GMainLoop *loop;
|
||||
|
||||
static void
|
||||
on_socket_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSocket *socket;
|
||||
GstElement *pipeline, *src;
|
||||
|
||||
g_object_get (gobject, "socket", &socket, NULL);
|
||||
g_print ("got socket %p\n", socket);
|
||||
|
||||
pipeline = gst_parse_launch ("socketsrc name=src ! pvfddepay ! "CAPS" ! videoconvert ! xvimagesink", NULL);
|
||||
src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
|
||||
|
||||
g_object_set (src, "socket", socket, NULL);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
}
|
||||
|
||||
static void
|
||||
on_stream_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvStreamState state;
|
||||
PvStream *s = user_data;
|
||||
|
||||
g_object_get (gobject, "state", &state, NULL);
|
||||
g_print ("got stream state %d\n", state);
|
||||
|
||||
switch (state) {
|
||||
case PV_STREAM_STATE_ERROR:
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
case PV_STREAM_STATE_READY:
|
||||
pv_stream_start (s, PV_STREAM_MODE_SOCKET);
|
||||
break;
|
||||
case PV_STREAM_STATE_STREAMING:
|
||||
{
|
||||
PvBufferInfo info;
|
||||
|
||||
pv_stream_capture_buffer (s, &info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_state_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContextState state;
|
||||
PvContext *c = user_data;
|
||||
|
||||
g_object_get (gobject, "state", &state, NULL);
|
||||
g_print ("got context state %d\n", state);
|
||||
|
||||
switch (state) {
|
||||
case PV_CONTEXT_STATE_ERROR:
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
case PV_CONTEXT_STATE_READY:
|
||||
{
|
||||
PvStream *stream;
|
||||
|
||||
stream = pv_stream_new (c, "test");
|
||||
g_signal_connect (stream, "notify::state", (GCallback) on_stream_notify, stream);
|
||||
g_signal_connect (stream, "notify::socket", (GCallback) on_socket_notify, stream);
|
||||
pv_stream_connect_capture (stream, NULL, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
PvContext *c;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
c = pv_context_new ("test-client", NULL);
|
||||
g_signal_connect (c, "notify::state", (GCallback) on_state_notify, c);
|
||||
pv_context_connect(c, PV_CONTEXT_FLAGS_NONE);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_object_unref (c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
76
src/tests/test-subscribe.c
Normal file
76
src/tests/test-subscribe.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* Pulsevideo
|
||||
* 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 <gst/gst.h>
|
||||
|
||||
#include <client/pv-context.h>
|
||||
#include <client/pv-subscribe.h>
|
||||
|
||||
static GMainLoop *loop;
|
||||
|
||||
static void
|
||||
subscription_cb (PvContext *context, PvSubscriptionEvent type, PvSubscriptionFlags flags,
|
||||
const gchar *object_path, gpointer user_data)
|
||||
{
|
||||
g_print ("got event %d %d %s\n", type, flags, object_path);
|
||||
}
|
||||
|
||||
static void
|
||||
on_state_notify (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContextState state;
|
||||
PvContext *c = user_data;
|
||||
|
||||
g_object_get (gobject, "state", &state, NULL);
|
||||
g_print ("got state %d\n", state);
|
||||
|
||||
switch (state) {
|
||||
case PV_CONTEXT_STATE_ERROR:
|
||||
g_main_loop_quit (loop);
|
||||
break;
|
||||
case PV_CONTEXT_STATE_READY:
|
||||
g_object_set (c, "subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL, NULL);
|
||||
g_signal_connect (c, "subscription-event", (GCallback) subscription_cb, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
PvContext *c;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
c = pv_context_new ("test-client", NULL);
|
||||
g_signal_connect (c, "notify::state", (GCallback) on_state_notify, c);
|
||||
pv_context_connect(c, PV_CONTEXT_FLAGS_NOFAIL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_object_unref (c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue