summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2006-05-08 22:08:33 +0000
committerLennart Poettering <lennart@poettering.net>2006-05-08 22:08:33 +0000
commitf8f641889aafafa817c9c03def299945cd23c018 (patch)
tree61dd971cc6f2cb95303483fe44717f9e86b6a87c
parentcb9e05efb2e784516b369b5bdc01329fe346aff9 (diff)
update for gstreamer 0.10 and polypaudio 0.8.1
git-svn-id: file:///home/lennart/svn/public/gst-pulse/trunk@14 bb39ca4e-bce3-0310-b5d4-eea78a553289
-rw-r--r--Makefile.am5
-rwxr-xr-xbootstrap.sh40
-rw-r--r--configure.ac14
-rw-r--r--src/Makefile.am11
-rw-r--r--src/plugin.c46
-rw-r--r--src/polypsink.c850
-rw-r--r--src/polypsink.h54
7 files changed, 525 insertions, 495 deletions
diff --git a/Makefile.am b/Makefile.am
index 6fafbc8..11e53bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,4 @@ homepage: all dist
cp doc/README.html doc/style.css $$HOME/homepage/private/projects/gst-polyp
cp $$HOME/homepage/private/projects/gst-polyp/README.html $$HOME/homepage/private/projects/gst-polyp/index.html
-distcleancheck:
- @:
-
-.PHONY: homepage distcleancheck
+.PHONY: homepage
diff --git a/bootstrap.sh b/bootstrap.sh
index b048d59..52ba247 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -17,31 +17,47 @@
# along with gst-polyp; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+VERSION=1.9
+
run_versioned() {
local P
- type -p "$1-$2" &> /dev/null && P="$1-$2" || local P="$1"
+ local V
+
+ V=$(echo "$2" | sed -e 's,\.,,g')
+
+ if [ -e "`which $1$V`" ] ; then
+ P="$1$V"
+ else
+ if [ -e "`which $1-$2`" ] ; then
+ P="$1-$2"
+ else
+ P="$1"
+ fi
+ fi
shift 2
"$P" "$@"
}
+set -ex
+
if [ "x$1" = "xam" ] ; then
- set -ex
- run_versioned automake 1.7 -a -c --foreign
+ run_versioned automake "$VERSION" -a -c --foreign
./config.status
else
- set -ex
-
rm -rf autom4te.cache
rm -f config.cache
- run_versioned aclocal 1.7
- libtoolize -c --force
- autoheader
- run_versioned automake 1.7 -a -c --foreign
- autoconf -Wall
+ test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize
- CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@"
+ "$LIBTOOLIZE" -c --force
+ run_versioned aclocal "$VERSION"
+ run_versioned autoconf 2.59 -Wall
+ run_versioned autoheader 2.59
+ run_versioned automake "$VERSION" -a -c --foreign
- make clean
+ if test "x$NOCONFIGURE" = "x"; then
+ CFLAGS="-g -O0" ./configure --sysconfdir=/etc "$@"
+ make clean
+ fi
fi
diff --git a/configure.ac b/configure.ac
index e3eff6f..3d8fecb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,10 +20,10 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
AC_PREREQ(2.57)
-AC_INIT([gst-polyp],[0.1.1],[mzkzzfcbylc (at) 0pointer (dot) de])
+AC_INIT([gst-polyp],[0.8.1],[mzkzzfcbylc (at) 0pointer (dot) de])
AC_CONFIG_SRCDIR([src/plugin.c])
AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE([foreign -Wall])
+AM_INIT_AUTOMAKE([foreign 1.9 -Wall])
AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/gst-polyp/])
@@ -43,20 +43,20 @@ AC_C_CONST
AC_FUNC_MALLOC
AC_TYPE_SIZE_T
-ACX_PTHREAD
+PKG_PROG_PKG_CONFIG
if test -d ../polypaudio ; then
- POLYP_CFLAGS='-I$(top_srcdir)/../polypaudio'
- POLYP_LIBS='-L$(top_srcdir)/../polypaudio/polyp -lpolyp-0.7 -lpolyp-error-0.7 -lpolyp-mainloop-0.7'
+ POLYP_CFLAGS='-I$(top_srcdir)/../polypaudio/src'
+ POLYP_LIBS='-L$(top_srcdir)/../polypaudio/src/.libs -lpolyp-0.8.1'
echo "*** Found polypaudio in ../polypaudio, using that version ***"
else
- PKG_CHECK_MODULES(POLYP, [ polyplib >= 0.7 ])
+ PKG_CHECK_MODULES(POLYP, [ polyplib >= 0.8.1 ])
fi
AC_SUBST(POLYP_LIBS)
AC_SUBST(POLYP_CFLAGS)
-PKG_CHECK_MODULES(GST, [ gstreamer-0.8 >= 0.8.4 ])
+PKG_CHECK_MODULES(GST, [ gstreamer-0.10 >= 0.10 gstreamer-plugins-base-0.10 >= 0.10 ])
AC_SUBST(GST_LIBS)
AC_SUBST(GST_CFLAGS)
diff --git a/src/Makefile.am b/src/Makefile.am
index 8423f27..26fc8b9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,14 +23,9 @@ pkglib_LTLIBRARIES = libgstpolyp.la
libgstpolyp_la_SOURCES = plugin.c polypsink.c polypsink.h
libgstpolyp_la_CFLAGS = $(GST_CFLAGS) $(POLYP_CFLAGS)
-libgstpolyp_la_LIBADD = $(POLYP_LIBS) $(GST_LIBS)
-
-install-exec-hook: reg
-
-reg:
- gst-register-0.8 --gst-plugin-path=$(pkglibdir)
+libgstpolyp_la_LIBADD = $(POLYP_LIBS) $(GST_LIBS) -lgstaudio-0.10
inspect:
- gst-inspect-0.8 polypsink
+ gst-inspect polypsink
-.PHONY: reg inspect
+.PHONY: inspect
diff --git a/src/plugin.c b/src/plugin.c
index 900fd17..9f99aea 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -1,3 +1,24 @@
+/* $Id$ */
+
+/***
+ This file is part of gst-polyp.
+
+ gst-polyp 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.
+
+ gst-polyp 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 gst-polyp; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -6,20 +27,23 @@
GST_DEBUG_CATEGORY(polyp_debug);
-static gboolean plugin_init (GstPlugin * plugin) {
- if (!gst_library_load("gstaudio"))
- return FALSE;
+static gboolean plugin_init(GstPlugin* plugin) {
- if (!(gst_polypsink_factory_init (plugin)))
+ if (!gst_element_register(plugin, "polypsink", GST_RANK_NONE, GST_TYPE_POLYPSINK))
return FALSE;
-
+
GST_DEBUG_CATEGORY_INIT(polyp_debug, "polyp", 0, "Polypaudio elements");
return TRUE;
}
-GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR,
- "polypsink", "Polypaudio Element Plugins",
- plugin_init,
- VERSION,
- "LGPL",
- "polypaudio", "http://0pointer.de/lennart/projects/gst-polyp/")
+GST_PLUGIN_DEFINE(
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "polypsink",
+ "Polypaudio Element Plugins",
+ plugin_init,
+ VERSION,
+ "LGPL",
+ "polypaudio",
+ "http://0pointer.de/lennart/projects/gst-polyp/"
+)
diff --git a/src/polypsink.c b/src/polypsink.c
index 835b63c..96c0c9f 100644
--- a/src/polypsink.c
+++ b/src/polypsink.c
@@ -1,579 +1,559 @@
-/*
- * This sink plugin works, but has some room for improvements:
- *
- * - Export polypaudio's stream clock through gstreamer's API
- * - Add support for querying latency information
- * - Add a source for polypaudio
- *
- * Lennart Poettering, 2004
- */
+/* $Id$ */
+
+/***
+ This file is part of gst-polyp.
+
+ gst-polyp 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.
+
+ gst-polyp 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 gst-polyp; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <pthread.h>
#include <string.h>
#include <stdio.h>
-#include <polyp/polyplib-error.h>
-#include <polyp/mainloop.h>
-
#include "polypsink.h"
+GST_DEBUG_CATEGORY_EXTERN(polyp_debug);
+#define GST_CAT_DEFAULT polyp_debug
+
enum {
- ARG_0,
- ARG_SERVER,
- ARG_SINK,
+ ARG_0,
+ ARG_SERVER,
+ ARG_SINK,
};
-static GstElementClass *parent_class = NULL;
+static GstAudioSinkClass *parent_class = NULL;
+
+static void gst_polypsink_destroy_stream(GstPolypSink *polypsink);
+static void gst_polypsink_destroy_context(GstPolypSink *polypsink);
-static void create_stream(GstPolypSink *polypsink);
-static void destroy_stream(GstPolypSink *polypsink);
+static void gst_polypsink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_polypsink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void gst_polypsink_finalize(GObject *object);
-static void create_context(GstPolypSink *polypsink);
-static void destroy_context(GstPolypSink *polypsink);
+static gboolean gst_polypsink_open(GstAudioSink *asink);
+static gboolean gst_polypsink_close(GstAudioSink *asink);
+
+static gboolean gst_polypsink_prepare(GstAudioSink *asink, GstRingBufferSpec *spec);
+static gboolean gst_polypsink_unprepare(GstAudioSink *asink);
+
+static guint gst_polypsink_write(GstAudioSink *asink, gpointer data, guint length);
+static guint gst_polypsink_delay(GstAudioSink *asink);
+static void gst_polypsink_reset(GstAudioSink *asink);
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+# define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
+#else
+# define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
+#endif
static void gst_polypsink_base_init(gpointer g_class) {
static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE(
- "sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS(
- "audio/x-raw-int, "
- "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
- "signed = (boolean) TRUE, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
-
- "audio/x-raw-float, "
- "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
- "width = (int) 32, "
- "rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
-
- "audio/x-raw-int, "
- "signed = (boolean) FALSE, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ]")
- );
-
- static const GstElementDetails details = {
- "Polypaudio Audio Sink",
- "Sink/Audio",
- "Plays audio to a Polypaudio server",
- "Lennart Poettering",
- };
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS(
+ "audio/x-raw-int, "
+ "endianness = (int) { " ENDIANNESS " }, "
+ "signed = (boolean) TRUE, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 16 ];"
+
+ "audio/x-raw-int, "
+ "signed = (boolean) FALSE, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 16 ];"
+
+ "audio/x-raw-float, "
+ "endianness = (int) { " ENDIANNESS " }, "
+ "width = (int) 32, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) [ 1, 16 ];"
+
+ "audio/x-alaw, "
+ "rate = (int) [ 1, MAX], "
+ "channels = (int) [ 1, 16 ];"
+
+ "audio/x-mulaw, "
+ "rate = (int) [ 1, MAX], "
+ "channels = (int) [ 1, 16 ]"
+ )
+ );
+ static const GstElementDetails details =
+ GST_ELEMENT_DETAILS(
+ "Polypaudio audio sink",
+ "Sink/Audio",
+ "Plays audio to a Polypaudio server",
+ "Lennart Poettering");
+
GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
- gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&pad_template));
+
gst_element_class_set_details(element_class, &details);
+ gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&pad_template));
}
-static void gst_polypsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
- GstPolypSink *polypsink;
- g_return_if_fail(GST_IS_POLYPSINK(object));
- polypsink = GST_POLYPSINK(object);
+static void gst_polypsink_class_init(
+ gpointer g_class,
+ gpointer class_data) {
- switch (prop_id) {
- case ARG_SERVER:
- g_free(polypsink->server);
- polypsink->server = g_strdup(g_value_get_string(value));
- break;
-
- case ARG_SINK:
- g_free(polypsink->sink);
- polypsink->sink = g_strdup(g_value_get_string(value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
+ GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
+// GstElementClass *gstelement_class = GST_ELEMENT_CLASS(g_class);
+ GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS(g_class);
+ parent_class = g_type_class_peek_parent(g_class);
+
+ gobject_class->set_property = gst_polypsink_set_property;
+ gobject_class->get_property = gst_polypsink_get_property;
+ gobject_class->finalize = gst_polypsink_finalize;
+
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR(gst_polypsink_open);
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR(gst_polypsink_close);
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR(gst_polypsink_prepare);
+ gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(gst_polypsink_unprepare);
+ gstaudiosink_class->write = GST_DEBUG_FUNCPTR(gst_polypsink_write);
+ gstaudiosink_class->delay = GST_DEBUG_FUNCPTR(gst_polypsink_delay);
+ gstaudiosink_class->reset = GST_DEBUG_FUNCPTR(gst_polypsink_reset);
+
+ /* Overwrite GObject fields */
+ g_object_class_install_property(
+ gobject_class,
+ ARG_SERVER,
+ g_param_spec_string("server", "Server", "The Polypaudio server to connect to", NULL, G_PARAM_READWRITE));
+ g_object_class_install_property(
+ gobject_class,
+ ARG_SINK,
+ g_param_spec_string("sink", "Sink", "The Polypaudio sink device to connect to", NULL, G_PARAM_READWRITE));
}
-static void gst_polypsink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec * pspec) {
- GstPolypSink *polypsink;
- g_return_if_fail(GST_IS_POLYPSINK(object));
- polypsink = GST_POLYPSINK(object);
+static void gst_polypsink_init(
+ GTypeInstance * instance,
+ gpointer g_class) {
- switch (prop_id) {
- case ARG_SERVER:
- g_value_set_string(value, polypsink->server);
- break;
-
- case ARG_SINK:
- g_value_set_string(value, polypsink->sink);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
+ GstPolypSink *polypsink = GST_POLYPSINK(instance);
+ int e;
-static GstElementStateReturn gst_polypsink_change_state(GstElement * element) {
- GstPolypSink *polypsink;
+ polypsink->server = polypsink->device = NULL;
- polypsink = GST_POLYPSINK (element);
+ polypsink->context = NULL;
+ polypsink->stream = NULL;
- switch(GST_STATE_TRANSITION(element)) {
-
- case GST_STATE_NULL_TO_READY:
- create_context(polypsink);
- break;
-
- case GST_STATE_READY_TO_NULL:
- destroy_context(polypsink);
- break;
+ polypsink->mainloop = pa_threaded_mainloop_new();
+ g_assert(polypsink->mainloop);
- case GST_STATE_READY_TO_PAUSED:
+ e = pa_threaded_mainloop_start(polypsink->mainloop);
+ g_assert(e == 0);
+}
- create_stream(polypsink);
+static void gst_polypsink_destroy_stream(GstPolypSink* polypsink) {
+ if (polypsink->stream) {
+ pa_stream_disconnect(polypsink->stream);
+ pa_stream_unref(polypsink->stream);
+ polypsink->stream = NULL;
+ }
+}
- if (polypsink->stream && pa_stream_get_state(polypsink->stream) == PA_STREAM_READY)
- pa_operation_unref(pa_stream_cork(polypsink->stream, 1, NULL, NULL));
- break;
-
- case GST_STATE_PLAYING_TO_PAUSED:
-
- if (polypsink->stream && pa_stream_get_state(polypsink->stream) == PA_STREAM_READY)
- pa_operation_unref(pa_stream_cork(polypsink->stream, 1, NULL, NULL));
+static void gst_polypsink_destroy_context(GstPolypSink* polypsink) {
- break;
+ gst_polypsink_destroy_stream(polypsink);
- case GST_STATE_PAUSED_TO_PLAYING:
+ if (polypsink->context) {
+ pa_context_disconnect(polypsink->context);
+ pa_context_unref(polypsink->context);
+ polypsink->context = NULL;
+ }
+}
- create_stream(polypsink);
+static void gst_polypsink_finalize(GObject * object) {
+ GstPolypSink *polypsink = GST_POLYPSINK(object);
- if (polypsink->stream && pa_stream_get_state(polypsink->stream) == PA_STREAM_READY)
- pa_operation_unref(pa_stream_cork(polypsink->stream, 0, NULL, NULL));
+ pa_threaded_mainloop_stop(polypsink->mainloop);
- break;
+ gst_polypsink_destroy_context(polypsink);
- case GST_STATE_PAUSED_TO_READY:
+ g_free(polypsink->server);
+ g_free(polypsink->device);
- destroy_stream(polypsink);
- break;
- }
-
- if (GST_ELEMENT_CLASS(parent_class)->change_state)
- return GST_ELEMENT_CLASS(parent_class)->change_state (element);
-
- return GST_STATE_SUCCESS;
-}
+ pa_threaded_mainloop_free(polypsink->mainloop);
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
-static void do_write(GstPolypSink *polypsink, size_t length) {
- size_t l;
+static void gst_polypsink_set_property(
+ GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec) {
- if (!polypsink->buffer)
- return;
-
- g_assert(polypsink->buffer_index < GST_BUFFER_SIZE(polypsink->buffer));
- l = GST_BUFFER_SIZE(polypsink->buffer) - polypsink->buffer_index;
+ GstPolypSink *polypsink = GST_POLYPSINK(object);
- if (l > length)
- l = length;
+ switch (prop_id) {
+ case ARG_SERVER:
+ g_free(polypsink->server);
+ polypsink->server = g_value_dup_string(value);
+ break;
- pa_stream_write(polypsink->stream, GST_BUFFER_DATA(polypsink->buffer) + polypsink->buffer_index, l, NULL, 0);
- polypsink->buffer_index += l;
+ case ARG_SINK:
+ g_free(polypsink->device);
+ polypsink->device = g_value_dup_string(value);
+ break;
- if (polypsink->buffer_index >= GST_BUFFER_SIZE(polypsink->buffer)) {
- gst_buffer_unref(polypsink->buffer);
- polypsink->buffer = NULL;
- polypsink->buffer_index = 0;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
}
}
-static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
- GstPolypSink *polypsink = userdata;
- g_assert(s && length && polypsink);
-
- do_write(polypsink, length);
-}
-
-static void stream_state_callback(struct pa_stream *s, void *userdata) {
- GstPolypSink *polypsink = userdata;
- g_assert(s && polypsink);
+static void gst_polypsink_get_property(
+ GObject * object,
+ guint prop_id,
+ GValue * value,
+ GParamSpec * pspec) {
+
+ GstPolypSink *polypsink = GST_POLYPSINK(object);
- switch (pa_stream_get_state(s)) {
- case PA_STREAM_DISCONNECTED:
- case PA_STREAM_CREATING:
+ switch(prop_id) {
+ case ARG_SERVER:
+ g_value_set_string(value, polypsink->server);
break;
- case PA_STREAM_READY:
+ case ARG_SINK:
+ g_value_set_string(value, polypsink->device);
break;
- case PA_STREAM_FAILED:
- GST_ELEMENT_ERROR(GST_ELEMENT(polypsink), RESOURCE, BUSY, ("Stream creation failed: %s", pa_strerror(pa_context_errno(pa_stream_get_context(s)))), (NULL));
-
- /* Pass over */
- case PA_STREAM_TERMINATED:
default:
- polypsink->mainloop_api->quit(polypsink->mainloop_api, 1);
- destroy_context(polypsink);
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
-static void context_state_callback(struct pa_context *c, void *userdata) {
- GstPolypSink *polypsink = userdata;
- g_assert(c && polypsink);
+static void gst_polypsink_context_state_cb(pa_context *c, void *userdata) {
+ GstPolypSink *polypsink = GST_POLYPSINK(userdata);
switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_READY:
+ case PA_CONTEXT_TERMINATED:
+ case PA_CONTEXT_FAILED:
+ pa_threaded_mainloop_signal(polypsink->mainloop, 0);
+ break;
+
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME:
break;
+ }
+}
+
+static void gst_polypsink_stream_state_cb(pa_stream *s, void * userdata) {
+ GstPolypSink *polypsink = GST_POLYPSINK(userdata);
- case PA_CONTEXT_READY: {
- GstElementState state;
- g_assert(!polypsink->stream);
-
- state = gst_element_get_state(GST_ELEMENT(polypsink));
- if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
- create_stream(polypsink);
-
+ switch (pa_stream_get_state(s)) {
+
+ case PA_STREAM_READY:
+ case PA_STREAM_FAILED:
+ case PA_STREAM_TERMINATED:
+ pa_threaded_mainloop_signal(polypsink->mainloop, 0);
break;
- }
-
- case PA_CONTEXT_FAILED:
- GST_ELEMENT_ERROR(GST_ELEMENT(polypsink), RESOURCE, BUSY, ("Connection failed: %s", pa_strerror(pa_context_errno(c))), (NULL));
- /* Pass over */
- case PA_CONTEXT_TERMINATED:
- default:
- polypsink->mainloop_api->quit(polypsink->mainloop_api, 1);
- destroy_context(polypsink);
+ case PA_STREAM_UNCONNECTED:
+ case PA_STREAM_CREATING:
break;
}
}
-static void create_stream(GstPolypSink *polypsink) {
- char t[256];
- g_assert(polypsink);
+static void gst_polypsink_stream_request_cb(pa_stream *s, size_t length, void *userdata) {
+ GstPolypSink *polypsink = GST_POLYPSINK(userdata);
- if (polypsink->stream)
- return;
+ pa_threaded_mainloop_signal(polypsink->mainloop, 0);
+}
- if (!polypsink->context) {
- create_context(polypsink);
- return;
- }
+static gboolean gst_polypsink_open(GstAudioSink *asink) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
- if (!polypsink->negotiated)
- return;
+ pa_threaded_mainloop_lock(polypsink->mainloop);
- if (pa_context_get_state(polypsink->context) != PA_CONTEXT_READY)
- return;
+ if (!(polypsink->context = pa_context_new(pa_threaded_mainloop_get_api(polypsink->mainloop), "gstreamer"))) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to create context"), (NULL));
+ goto unlock_and_fail;
+ }
- pa_sample_spec_snprint(t, sizeof(t), &polypsink->sample_spec);
+ pa_context_set_state_callback(polypsink->context, gst_polypsink_context_state_cb, polypsink);
- polypsink->stream = pa_stream_new(polypsink->context, "gstreamer output", &polypsink->sample_spec);
- g_assert(polypsink->stream);
-
- pa_stream_set_state_callback(polypsink->stream, stream_state_callback, polypsink);
- pa_stream_set_write_callback(polypsink->stream, stream_write_callback, polypsink);
- pa_stream_connect_playback(polypsink->stream, NULL, NULL, PA_STREAM_INTERPOLATE_LATENCY, PA_VOLUME_NORM);
-}
+ if (pa_context_connect(polypsink->context, polypsink->server, 0, NULL) < 0) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to connect: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
-static void create_context(GstPolypSink *polypsink) {
- g_assert(polypsink);
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait(polypsink->mainloop);
- if (polypsink->context)
- return;
+ if (pa_context_get_state(polypsink->context) != PA_CONTEXT_READY) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to connect: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- polypsink->context = pa_context_new(polypsink->mainloop_api, "gstreamer");
- g_assert(polypsink->context);
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+ return TRUE;
- pa_context_set_state_callback(polypsink->context, context_state_callback, polypsink);
- pa_context_connect(polypsink->context, NULL, 1, NULL);
+unlock_and_fail:
+
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+ return FALSE;
}
-static void destroy_stream(GstPolypSink *polypsink) {
- g_assert(polypsink);
+static gboolean gst_polypsink_close(GstAudioSink *asink) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
- if (polypsink->stream) {
- struct pa_stream *s = polypsink->stream;
- polypsink->stream = NULL;
- pa_stream_set_state_callback(s, NULL, NULL);
- pa_stream_set_write_callback(s, NULL, NULL);
- pa_stream_unref(s);
- }
+ pa_threaded_mainloop_lock(polypsink->mainloop);
+ gst_polypsink_destroy_context(polypsink);
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+
+ return TRUE;
}
-static void destroy_context(GstPolypSink *polypsink) {
- destroy_stream(polypsink);
+static gboolean gst_polypsink_fill_sample_spec(GstRingBufferSpec *spec, pa_sample_spec *ss) {
+
+ if (spec->format == GST_MU_LAW && spec->width == 8)
+ ss->format = PA_SAMPLE_ULAW;
+ else if (spec->format == GST_A_LAW && spec->width == 8)
+ ss->format = PA_SAMPLE_ALAW;
+ else if (spec->format == GST_U8 && spec->width == 8)
+ ss->format = PA_SAMPLE_U8;
+ else if (spec->format == GST_S16_LE && spec->width == 16)
+ ss->format = PA_SAMPLE_S16LE;
+ else if (spec->format == GST_S16_BE && spec->width == 16)
+ ss->format = PA_SAMPLE_S16BE;
+ else if (spec->format == GST_FLOAT32_LE && spec->width == 32)
+ ss->format = PA_SAMPLE_FLOAT32LE;
+ else if (spec->format == GST_FLOAT32_BE && spec->width == 32)
+ ss->format = PA_SAMPLE_FLOAT32BE;
+ else
+ return FALSE;
- if (polypsink->context) {
- struct pa_context *c = polypsink->context;
- polypsink->context = NULL;
- pa_context_set_state_callback(c, NULL, NULL);
- pa_context_unref(c);
- }
+ ss->channels = spec->channels;
+ ss->rate = spec->rate;
+
+ if (!pa_sample_spec_valid(ss))
+ return FALSE;
+
+ return TRUE;
}
-static void gst_polypsink_chain(GstPad *pad, GstData *data) {
- GstPolypSink *polypsink = GST_POLYPSINK(gst_pad_get_parent(pad));
+static gboolean gst_polypsink_prepare(GstAudioSink *asink, GstRingBufferSpec *spec) {
+ pa_buffer_attr buf_attr;
+
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
- g_assert(!polypsink->buffer);
+ if (!gst_polypsink_fill_sample_spec(spec, &polypsink->sample_spec)) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, SETTINGS, ("Invalid sample specification."), (NULL));
+ goto unlock_and_fail;
+ }
- if (GST_IS_EVENT(data)) {
- GstEvent *event = GST_EVENT(data);
-
- switch (GST_EVENT_TYPE(event)) {
- case GST_EVENT_EOS:
- if (polypsink->stream) {
- struct pa_operation *o;
-
- pa_operation_unref(pa_stream_cork(polypsink->stream, 0, NULL, NULL));
- o = pa_stream_drain(polypsink->stream, NULL, NULL);
-
- /* drain now */
- while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
- if (pa_mainloop_iterate(polypsink->mainloop, 1, NULL) < 0)
- return;
- }
-
- pa_operation_unref(o);
- }
-
- break;
- case GST_EVENT_FLUSH:
- if (polypsink->stream)
- pa_operation_unref(pa_stream_flush(polypsink->stream, NULL, NULL));
- break;
-
- default:
- break;
- }
-
- gst_pad_event_default(polypsink->sinkpad, event);
- } else {
- size_t l;
- polypsink->buffer = GST_BUFFER(data);
- polypsink->buffer_index = 0;
- polypsink->counter += GST_BUFFER_SIZE(polypsink->buffer);
-
- if (polypsink->stream && (l = pa_stream_writable_size(polypsink->stream)) > 0)
- do_write(polypsink, l);
+ pa_threaded_mainloop_lock(polypsink->mainloop);
+
+ if (!polypsink->context || pa_context_get_state(polypsink->context) != PA_CONTEXT_READY) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Bad context state: %s", polypsink->context ? pa_strerror(pa_context_errno(polypsink->context)) : NULL), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (!(polypsink->stream = pa_stream_new(polypsink->context, "the stream", &polypsink->sample_spec, NULL))) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to create stream: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
}
- while (polypsink->context && (pa_context_is_pending(polypsink->context) || polypsink->buffer)) {
- if (pa_mainloop_iterate(polypsink->mainloop, 1, NULL) < 0)
- return;
+ pa_stream_set_state_callback(polypsink->stream, gst_polypsink_stream_state_cb, polypsink);
+ pa_stream_set_write_callback(polypsink->stream, gst_polypsink_stream_request_cb, polypsink);
+
+ memset(&buf_attr, 0, sizeof(buf_attr));
+ buf_attr.tlength = spec->segtotal*spec->segsize;
+ buf_attr.maxlength = buf_attr.tlength*2;
+ buf_attr.prebuf = buf_attr.minreq = spec->segsize;
+
+ if (pa_stream_connect_playback(polypsink->stream, polypsink->device, &buf_attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_NOT_MONOTONOUS, NULL, NULL) < 0) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to connext stream: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
}
-}
+ /* Wait until the stream is ready */
+ pa_threaded_mainloop_wait(polypsink->mainloop);
-#if 0
-static void stream_get_latency_callback(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) {
- GstPolypSink *polypsink = (GstPolypSink*) userdata;
+ if (pa_stream_get_state(polypsink->stream) != PA_STREAM_READY) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Failed to connext stream: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- polypsink->latency = i->buffer_usec + i->sink_usec;
-}
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
-static GstClockTime gst_polypsink_get_time(GstClock *clock, gpointer data) {
- struct pa_operation *o;
- GstPolypSink *polypsink = GST_POLYPSINK(data);
- GstClockTime r, l;
+ spec->bytes_per_sample = pa_frame_size(&polypsink->sample_spec);
+ memset(spec->silence_sample, 0, spec->bytes_per_sample);
- if (!polypsink->stream || pa_stream_get_state(polypsink->stream) != PA_STREAM_READY)
- return 0;
+ return TRUE;
- polypsink->latency = 0;
+unlock_and_fail:
- o = pa_stream_get_latency(polypsink_>stream, latency_func, polypsink);
- g_assert(o);
-
- while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
- if (pa_mainloop_iterate(polypsink->mainloop, 1, NULL) < 0)
- return;
- }
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+ return FALSE;
+}
- r = ((GstClockTime) polypsink->counter / pa_frame_size(&polypsink->sample_spec))*GST_SECOND/polypsink->sample_spec.rate;
- l = polypsink->latency*GST_USECOND;
+static gboolean gst_polypsink_unprepare(GstAudioSink * asink) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
- return r > l ? r - l : 0;
-}
+ pa_threaded_mainloop_lock(polypsink->mainloop);
+ gst_polypsink_destroy_stream(polypsink);
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
-static GstClock *gst_polypsink_get_clock(GstElement * element) {
- GstPolypSink *polypsink = GST_POLYPSINK (element);
- return GST_CLOCK (polypsink->provided_clock);
+ return TRUE;
}
-static void gst_polypsink_set_clock (GstElement * element, GstClock * clock) {
- GstPolypSink *polypsink = GST_POLYPSINK (element);
- polypsink->clock = clock;
+#define CHECK_DEAD_GOTO(polypsink, label) \
+if (!(polypsink)->context || pa_context_get_state((polypsink)->context) != PA_CONTEXT_READY || \
+ !(polypsink)->stream || pa_stream_get_state((polypsink)->stream) != PA_STREAM_READY) { \
+ GST_ELEMENT_ERROR((polypsink), RESOURCE, FAILED, ("Disconnected: %s", (polypsink)->context ? pa_strerror(pa_context_errno((polypsink)->context)) : NULL), (NULL)); \
+ goto label; \
}
-#endif
-
-static GstPadLinkReturn gst_polypsink_link(GstPad *pad, const GstCaps *caps) {
- int depth = 16, endianness = 1234;
- gboolean sign = TRUE;
- GstPolypSink *polypsink;
- GstStructure *structure;
- const char *n;
- char t[256];
- GstElementState state;
-
- polypsink = GST_POLYPSINK(gst_pad_get_parent(pad));
-
- structure = gst_caps_get_structure(caps, 0);
-
- if (!(gst_structure_get_int(structure, "depth", &depth)))
- gst_structure_get_int(structure, "width", &depth);
-
- gst_structure_get_int(structure, "endianness", &endianness);
- gst_structure_get_boolean(structure, "signed", &sign);
-
- n = gst_structure_get_name(structure);
-
- if (depth == 16 && endianness == 1234 && sign && !strcmp(n, "audio/x-raw-int"))
- polypsink->sample_spec.format = PA_SAMPLE_S16LE;
- else if (depth == 16 && endianness == 4321 && sign && !strcmp(n, "audio/x-raw-int"))
- polypsink->sample_spec.format = PA_SAMPLE_S16BE;
- else if (depth == 8 && !sign && !strcmp(n, "audio/x-raw-int"))
- polypsink->sample_spec.format = PA_SAMPLE_U8;
- else if (depth == 32 && endianness == 1234 && !strcmp(n, "audio/x-raw-float"))
- polypsink->sample_spec.format = PA_SAMPLE_FLOAT32LE;
- else if (depth == 32 && endianness == 4321 && !strcmp(n, "audio/x-raw-float"))
- polypsink->sample_spec.format = PA_SAMPLE_FLOAT32LE;
- else
- return GST_PAD_LINK_REFUSED;
-
- polypsink->sample_spec.rate = 44100;
- polypsink->sample_spec.channels = 2;
-
- pa_sample_spec_snprint(t, sizeof(t), &polypsink->sample_spec);
+static guint gst_polypsink_write(GstAudioSink *asink, gpointer data, guint length) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
+ size_t l;
- gst_structure_get_int(structure, "channels", (int*) &polypsink->sample_spec.channels);
- gst_structure_get_int(structure, "rate", &polypsink->sample_spec.rate);
+ pa_threaded_mainloop_lock(polypsink->mainloop);
- pa_sample_spec_snprint(t, sizeof(t), &polypsink->sample_spec);
-
- if (!pa_sample_spec_valid(&polypsink->sample_spec))
- return GST_PAD_LINK_REFUSED;
+ for (;;) {
+ CHECK_DEAD_GOTO(polypsink, unlock_and_fail);
-
+ if ((l = pa_stream_writable_size(polypsink->stream)))
+ break;
+
+ pa_threaded_mainloop_wait(polypsink->mainloop);
+ }
- polypsink->negotiated = 1;
+ if (l == (size_t) -1) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- destroy_stream(polypsink);
+ if (l > length)
+ l = length;
- state = gst_element_get_state(GST_ELEMENT(polypsink));
- if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
- create_stream(polypsink);
+ if (pa_stream_write(polypsink->stream, data, l, NULL, 0, PA_SEEK_RELATIVE) < 0) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("pa_stream_write() failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- return GST_PAD_LINK_OK;
-}
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
-static GstCaps* gst_polypsink_sink_fixate(GstPad *pad, const GstCaps *caps) {
- GstCaps *newcaps;
- GstStructure *structure;
+ GST_WARNING("Write");
- newcaps = gst_caps_new_full(gst_structure_copy(gst_caps_get_structure(caps, 0)), NULL);
- structure = gst_caps_get_structure(newcaps, 0);
+ return l;
+unlock_and_fail:
- if (gst_caps_structure_fixate_field_nearest_int (structure, "rate", 44100) ||
- gst_caps_structure_fixate_field_nearest_int (structure, "depth", 16) ||
- gst_caps_structure_fixate_field_nearest_int (structure, "width", 16) ||
- gst_caps_structure_fixate_field_nearest_int (structure, "channels", 2))
- return newcaps;
-
- gst_caps_free (newcaps);
- return NULL;
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+ return 0;
}
-static void gst_polypsink_init(GTypeInstance* instance, gpointer g_class) {
- GstPolypSink *polypsink = GST_POLYPSINK(instance);
+static guint gst_polypsink_delay(GstAudioSink *asink) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
+ pa_usec_t t;
- polypsink->sinkpad = gst_pad_new_from_template(gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS (instance), "sink"), "sink");
-
- gst_element_add_pad(GST_ELEMENT(polypsink), polypsink->sinkpad);
- gst_pad_set_chain_function(polypsink->sinkpad, gst_polypsink_chain);
- gst_pad_set_link_function(polypsink->sinkpad, gst_polypsink_link);
- gst_pad_set_fixate_function (polypsink->sinkpad, gst_polypsink_sink_fixate);
-
-/* GST_FLAG_SET(polypsink, GST_ELEMENT_THREAD_SUGGESTED); */
- GST_FLAG_SET(polypsink, GST_ELEMENT_EVENT_AWARE);
-
- polypsink->context = NULL;
- polypsink->stream = NULL;
+ pa_threaded_mainloop_lock(polypsink->mainloop);
- polypsink->mainloop = pa_mainloop_new();
- g_assert(polypsink->mainloop);
+ CHECK_DEAD_GOTO(polypsink, unlock_and_fail);
- polypsink->mainloop_api = pa_mainloop_get_api(polypsink->mainloop);
+ if (pa_stream_get_latency(polypsink->stream, &t, NULL) < 0) {
- polypsink->sample_spec.rate = 0;
- polypsink->sample_spec.channels = 0;
- polypsink->sample_spec.format = 0;
+ if (pa_context_errno(polypsink->context) != PA_ERR_NODATA) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("pa_stream_get_latency() failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- polypsink->negotiated = 0;
+ GST_WARNING("Not data while querying latency");
+ t = 0;
+ }
- polypsink->buffer = NULL;
- polypsink->buffer_index = 0;
+ GST_WARNING("Latency %0.3f ms", (double) t / 1000);
+
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+
+ return (guint) ((t * polypsink->sample_spec.rate) / 1000000LL);
- polypsink->latency = 0;
- polypsink->counter = 0;
+unlock_and_fail:
+
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
+ return 0;
}
-static void gst_polypsink_dispose(GObject *object) {
- GstPolypSink *polypsink = GST_POLYPSINK(object);
+static void gst_polypsink_success_cb(pa_stream *s, int success, void *userdata) {
+ GstPolypSink *polypsink = GST_POLYPSINK(userdata);
-/* gst_object_unparent(GST_OBJECT(polypsink->provided_clock)); */
+ polypsink->operation_success = success;
+ pa_threaded_mainloop_signal(polypsink->mainloop, 0);
+}
+static void gst_polypsink_reset(GstAudioSink *asink) {
+ GstPolypSink *polypsink = GST_POLYPSINK(asink);
+ pa_operation *o = NULL;
- destroy_context(polypsink);
+ pa_threaded_mainloop_lock(polypsink->mainloop);
- if (polypsink->buffer)
- gst_buffer_unref(polypsink->buffer);
+ CHECK_DEAD_GOTO(polypsink, unlock_and_fail);
-
- g_free(polypsink->server);
- g_free(polypsink->sink);
+ if (!(o = pa_stream_flush(polypsink->stream, gst_polypsink_success_cb, polypsink))) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("pa_stream_flush() failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
- pa_mainloop_free(polypsink->mainloop);
-
- G_OBJECT_CLASS(parent_class)->dispose(object);
-}
-
-static void gst_polypsink_class_init(gpointer g_class, gpointer class_data) {
- GObjectClass *gobject_class = G_OBJECT_CLASS(g_class);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS(g_class);
-
- parent_class = g_type_class_peek_parent(g_class);
+ polypsink->operation_success = 0;
+ while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
+ CHECK_DEAD_GOTO(polypsink, unlock_and_fail);
+
+ pa_threaded_mainloop_wait(polypsink->mainloop);
+ }
- g_object_class_install_property(gobject_class, ARG_SERVER, g_param_spec_string("server", "server", "server", NULL, G_PARAM_READWRITE));
- g_object_class_install_property(gobject_class, ARG_SINK, g_param_spec_string("sink", "sink", "sink", NULL, G_PARAM_READWRITE));
+ GST_WARNING("Reset");
- gobject_class->set_property = gst_polypsink_set_property;
- gobject_class->get_property = gst_polypsink_get_property;
- gobject_class->dispose = gst_polypsink_dispose;
-
- gstelement_class->change_state = gst_polypsink_change_state;
-/* gstelement_class->set_clock = gst_polypsink_set_clock; */
-/* gstelement_class->get_clock = gst_polypsink_get_clock; */
-}
+ if (!polypsink->operation_success) {
+ GST_ELEMENT_ERROR(polypsink, RESOURCE, FAILED, ("Flush failed: %s", pa_strerror(pa_context_errno(polypsink->context))), (NULL));
+ goto unlock_and_fail;
+ }
+unlock_and_fail:
-gboolean gst_polypsink_factory_init(GstPlugin *plugin) {
- return gst_element_register(plugin, "polypsink", GST_RANK_NONE, GST_TYPE_POLYPSINK);
+ if (o) {
+ pa_operation_cancel(o);
+ pa_operation_unref(o);
+ }
+
+ pa_threaded_mainloop_unlock(polypsink->mainloop);
}
GType gst_polypsink_get_type(void) {
static GType polypsink_type = 0;
if (!polypsink_type) {
-
+
static const GTypeInfo polypsink_info = {
- sizeof (GstPolypSinkClass),
+ sizeof(GstPolypSinkClass),
gst_polypsink_base_init,
NULL,
gst_polypsink_class_init,
@@ -583,9 +563,13 @@ GType gst_polypsink_get_type(void) {
0,
gst_polypsink_init,
};
-
- polypsink_type = g_type_register_static(GST_TYPE_ELEMENT, "GstPolypSink", &polypsink_info, 0);
+
+ polypsink_type = g_type_register_static(
+ GST_TYPE_AUDIO_SINK,
+ "GstPolypSink",
+ &polypsink_info,
+ 0);
}
-
+
return polypsink_type;
}
diff --git a/src/polypsink.h b/src/polypsink.h
index 90b3b7e..4b9a76b 100644
--- a/src/polypsink.h
+++ b/src/polypsink.h
@@ -1,10 +1,32 @@
#ifndef __GST_POLYPSINK_H__
#define __GST_POLYPSINK_H__
+/* $Id$ */
+
+/***
+ This file is part of gst-polyp.
+
+ gst-polyp 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.
+
+ gst-polyp 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 gst-polyp; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
#include <gst/gst.h>
+#include </usr/include/gstreamer-0.10/gst/audio/gstaudiosink.h>
-#include <polyp/polyplib-context.h>
-#include <polyp/polyplib-stream.h>
+#include <polyp/polypaudio.h>
+#include <polyp/thread-mainloop.h>
G_BEGIN_DECLS
@@ -23,33 +45,25 @@ typedef struct _GstPolypSink GstPolypSink;
typedef struct _GstPolypSinkClass GstPolypSinkClass;
struct _GstPolypSink {
- GstElement element;
-
- GstPad *sinkpad;
-
- char *server, *sink;
-
- struct pa_mainloop *mainloop;
- struct pa_mainloop_api *mainloop_api;
- struct pa_context *context;
- struct pa_stream *stream;
- struct pa_sample_spec sample_spec;
+ GstAudioSink sink;
- int negotiated;
+ gchar *server, *device;
- GstBuffer *buffer;
- size_t buffer_index;
+ pa_threaded_mainloop *mainloop;
+
+ pa_context *context;
+ pa_stream *stream;
+
+ pa_sample_spec sample_spec;
- size_t counter;
- pa_usec_t latency;
+ int operation_success;
};
struct _GstPolypSinkClass {
- GstElementClass parent_class;
+ GstAudioSinkClass parent_class;
};
GType gst_polypsink_get_type(void);
-gboolean gst_polypsink_factory_init(GstPlugin *plugin);
G_END_DECLS