mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
Added the polypaudio sink and hooked it into the build system.
Original commit message from CVS: Added the polypaudio sink and hooked it into the build system.
This commit is contained in:
parent
c39ed546c7
commit
0548c56447
7 changed files with 820 additions and 0 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2004-11-12 Iain <iaingnome@gmail.com>
|
||||
|
||||
* configure.ac: Check for polypaudio
|
||||
|
||||
* ext/Makefile.am: Build the polyp dir
|
||||
|
||||
* ext/polyp: The polypsink sources.
|
||||
|
||||
2004-10-30 Iain <iaingnome@gmail.com>
|
||||
|
||||
* gst/interleave/interleave.c (interleave_unlink): Change the src pads
|
||||
caps to reflect the new number of channels.
|
||||
|
||||
2004-11-12 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
|
||||
* ext/alsa/gstalsasink.c: (gst_alsa_sink_loop):
|
||||
|
|
11
configure.ac
11
configure.ac
|
@ -1411,6 +1411,15 @@ GST_CHECK_FEATURE(PANGO, [pango], pango, [
|
|||
AC_SUBST(PANGO_LIBS)
|
||||
])
|
||||
|
||||
dnl *** polypaudio ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_POLYP, true)
|
||||
GST_CHECK_FEATURE(POLYP, [polyp], polyp, [
|
||||
PKG_CHECK_MODULES(POLYP, polyplib >= 0.6,
|
||||
HAVE_POLYP="yes", HAVE_POLYP="no")
|
||||
AC_SUBST(POLYP_CFLAGS)
|
||||
AC_SUBST(POLYP_CFLAGS)
|
||||
])
|
||||
|
||||
dnl *** dv1394 ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_DV1394, true)
|
||||
GST_CHECK_FEATURE(DV1394, [raw1394 and avc1394 library], dv1394src, [
|
||||
|
@ -1970,6 +1979,7 @@ ext/musicbrainz/Makefile
|
|||
ext/nas/Makefile
|
||||
ext/ogg/Makefile
|
||||
ext/pango/Makefile
|
||||
ext/polyp/Makefile
|
||||
ext/raw1394/Makefile
|
||||
ext/sdl/Makefile
|
||||
ext/shout/Makefile
|
||||
|
@ -1988,6 +1998,7 @@ ext/xvid/Makefile
|
|||
gst-libs/Makefile
|
||||
gst-libs/gst/Makefile
|
||||
gst-libs/gst/audio/Makefile
|
||||
gst-libs/gst/cache/Makefile
|
||||
gst-libs/gst/colorbalance/Makefile
|
||||
gst-libs/gst/floatcast/Makefile
|
||||
gst-libs/gst/gconf/Makefile
|
||||
|
|
|
@ -190,6 +190,12 @@ else
|
|||
LIBPNG_DIR=
|
||||
endif
|
||||
|
||||
if USE_POLYP
|
||||
POLYP_DIR=polyp
|
||||
else
|
||||
POLYP_DIR=
|
||||
endif
|
||||
|
||||
if USE_LIBRFB
|
||||
LIBRFB_DIR=librfb
|
||||
else
|
||||
|
@ -409,6 +415,7 @@ SUBDIRS=\
|
|||
$(MUSICBRAINZ_DIR) \
|
||||
$(OGG_DIR) \
|
||||
$(PANGO_DIR) \
|
||||
$(POLYP_DIR) \
|
||||
$(SDL_DIR) \
|
||||
$(SHOUT_DIR) \
|
||||
$(SHOUT2_DIR) \
|
||||
|
@ -470,6 +477,7 @@ DIST_SUBDIRS=\
|
|||
nas \
|
||||
ogg \
|
||||
pango \
|
||||
polyp \
|
||||
raw1394 \
|
||||
sdl \
|
||||
snapshot \
|
||||
|
|
9
ext/polyp/Makefile.am
Normal file
9
ext/polyp/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
plugin_LTLIBRARIES = libpolypaudio.la
|
||||
|
||||
libpolypaudio_la_SOURCES = plugin.c polypsink.c
|
||||
libpolypaudio_la_CFLAGS = $(GST_CFLAGS)
|
||||
libpolypaudio_la_LIBADD = $(GST_LIBS) $(POLYP_LIBS)
|
||||
libpolypaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = polypsink.h
|
26
ext/polyp/plugin.c
Normal file
26
ext/polyp/plugin.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "polypsink.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (polyp_debug);
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_library_load ("gstaudio"))
|
||||
return FALSE;
|
||||
|
||||
if (!(gst_polypsink_factory_init (plugin)))
|
||||
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/")
|
694
ext/polyp/polypsink.c
Normal file
694
ext/polyp/polypsink.c
Normal file
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <polyp/polyplib-error.h>
|
||||
#include <polyp/mainloop.h>
|
||||
|
||||
#include "polypsink.h"
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
ARG_SERVER,
|
||||
ARG_SINK,
|
||||
};
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
static void create_stream (GstPolypSink * polypsink);
|
||||
static void destroy_stream (GstPolypSink * polypsink);
|
||||
|
||||
static void create_context (GstPolypSink * polypsink);
|
||||
static void destroy_context (GstPolypSink * polypsink);
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_polypsink_change_state (GstElement * element)
|
||||
{
|
||||
GstPolypSink *polypsink;
|
||||
|
||||
polypsink = GST_POLYPSINK (element);
|
||||
|
||||
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;
|
||||
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
|
||||
create_stream (polypsink);
|
||||
|
||||
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));
|
||||
|
||||
break;
|
||||
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
|
||||
create_stream (polypsink);
|
||||
|
||||
if (polypsink->stream
|
||||
&& pa_stream_get_state (polypsink->stream) == PA_STREAM_READY)
|
||||
pa_operation_unref (pa_stream_cork (polypsink->stream, 0, NULL, NULL));
|
||||
|
||||
break;
|
||||
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_write (GstPolypSink * polypsink, size_t length)
|
||||
{
|
||||
size_t l;
|
||||
|
||||
if (!polypsink->buffer)
|
||||
return;
|
||||
|
||||
g_assert (polypsink->buffer_index < GST_BUFFER_SIZE (polypsink->buffer));
|
||||
l = GST_BUFFER_SIZE (polypsink->buffer) - polypsink->buffer_index;
|
||||
|
||||
if (l > length)
|
||||
l = length;
|
||||
|
||||
pa_stream_write (polypsink->stream,
|
||||
GST_BUFFER_DATA (polypsink->buffer) + polypsink->buffer_index, l, NULL,
|
||||
0);
|
||||
polypsink->buffer_index += l;
|
||||
|
||||
if (polypsink->buffer_index >= GST_BUFFER_SIZE (polypsink->buffer)) {
|
||||
gst_buffer_unref (polypsink->buffer);
|
||||
polypsink->buffer = NULL;
|
||||
polypsink->buffer_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
switch (pa_stream_get_state (s)) {
|
||||
case PA_STREAM_DISCONNECTED:
|
||||
case PA_STREAM_CREATING:
|
||||
break;
|
||||
|
||||
case PA_STREAM_READY:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
context_state_callback (struct pa_context *c, void *userdata)
|
||||
{
|
||||
GstPolypSink *polypsink = userdata;
|
||||
|
||||
g_assert (c && polypsink);
|
||||
|
||||
switch (pa_context_get_state (c)) {
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
break;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
create_stream (GstPolypSink * polypsink)
|
||||
{
|
||||
char t[256];
|
||||
|
||||
g_assert (polypsink);
|
||||
|
||||
if (polypsink->stream)
|
||||
return;
|
||||
|
||||
if (!polypsink->context) {
|
||||
create_context (polypsink);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!polypsink->negotiated)
|
||||
return;
|
||||
|
||||
if (pa_context_get_state (polypsink->context) != PA_CONTEXT_READY)
|
||||
return;
|
||||
|
||||
pa_sample_spec_snprint (t, sizeof (t), &polypsink->sample_spec);
|
||||
|
||||
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);
|
||||
|
||||
while (polypsink->context && pa_context_is_pending (polypsink->context)) {
|
||||
if (pa_mainloop_iterate (polypsink->mainloop, 1, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
create_context (GstPolypSink * polypsink)
|
||||
{
|
||||
g_assert (polypsink);
|
||||
|
||||
if (polypsink->context)
|
||||
return;
|
||||
|
||||
polypsink->context = pa_context_new (polypsink->mainloop_api, "gstreamer");
|
||||
g_assert (polypsink->context);
|
||||
|
||||
pa_context_set_state_callback (polypsink->context, context_state_callback,
|
||||
polypsink);
|
||||
pa_context_connect (polypsink->context, NULL, 1, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_stream (GstPolypSink * polypsink)
|
||||
{
|
||||
g_assert (polypsink);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_context (GstPolypSink * polypsink)
|
||||
{
|
||||
destroy_stream (polypsink);
|
||||
|
||||
if (polypsink->context) {
|
||||
struct pa_context *c = polypsink->context;
|
||||
|
||||
polypsink->context = NULL;
|
||||
pa_context_set_state_callback (c, NULL, NULL);
|
||||
pa_context_unref (c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_polypsink_chain (GstPad * pad, GstData * data)
|
||||
{
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (gst_pad_get_parent (pad));
|
||||
|
||||
g_assert (!polypsink->buffer);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
while (polypsink->context && (pa_context_is_pending (polypsink->context)
|
||||
|| polypsink->buffer)) {
|
||||
if (pa_mainloop_iterate (polypsink->mainloop, 1, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
stream_get_latency_callback (struct pa_stream *s,
|
||||
const struct pa_latency_info *i, void *userdata)
|
||||
{
|
||||
GstPolypSink *polypsink = (GstPolypSink *) userdata;
|
||||
|
||||
polypsink->latency = i->buffer_usec + i->sink_usec;
|
||||
}
|
||||
|
||||
static GstClockTime
|
||||
gst_polypsink_get_time (GstClock * clock, gpointer data)
|
||||
{
|
||||
struct pa_operation *o;
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (data);
|
||||
GstClockTime r, l;
|
||||
|
||||
if (!polypsink->stream
|
||||
|| pa_stream_get_state (polypsink->stream) != PA_STREAM_READY)
|
||||
return 0;
|
||||
|
||||
polypsink->latency = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
r = ((GstClockTime) polypsink->counter /
|
||||
pa_frame_size (&polypsink->sample_spec)) * GST_SECOND /
|
||||
polypsink->sample_spec.rate;
|
||||
l = polypsink->latency * GST_USECOND;
|
||||
|
||||
return r > l ? r - l : 0;
|
||||
}
|
||||
|
||||
static GstClock *
|
||||
gst_polypsink_get_clock (GstElement * element)
|
||||
{
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (element);
|
||||
|
||||
return GST_CLOCK (polypsink->provided_clock);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_polypsink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (element);
|
||||
|
||||
polypsink->clock = clock;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
gst_structure_get_int (structure, "channels",
|
||||
(int *) &polypsink->sample_spec.channels);
|
||||
gst_structure_get_int (structure, "rate", &polypsink->sample_spec.rate);
|
||||
|
||||
pa_sample_spec_snprint (t, sizeof (t), &polypsink->sample_spec);
|
||||
|
||||
if (!pa_sample_spec_valid (&polypsink->sample_spec))
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
|
||||
|
||||
|
||||
polypsink->negotiated = 1;
|
||||
|
||||
destroy_stream (polypsink);
|
||||
|
||||
state = gst_element_get_state (GST_ELEMENT (polypsink));
|
||||
if (state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
|
||||
create_stream (polypsink);
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_polypsink_sink_fixate (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
GstCaps *newcaps;
|
||||
GstStructure *structure;
|
||||
|
||||
newcaps =
|
||||
gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (caps, 0)),
|
||||
NULL);
|
||||
structure = gst_caps_get_structure (newcaps, 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_polypsink_init (GTypeInstance * instance, gpointer g_class)
|
||||
{
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (instance);
|
||||
|
||||
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;
|
||||
|
||||
polypsink->mainloop = pa_mainloop_new ();
|
||||
g_assert (polypsink->mainloop);
|
||||
|
||||
polypsink->mainloop_api = pa_mainloop_get_api (polypsink->mainloop);
|
||||
|
||||
polypsink->sample_spec.rate = 0;
|
||||
polypsink->sample_spec.channels = 0;
|
||||
polypsink->sample_spec.format = 0;
|
||||
|
||||
polypsink->negotiated = 0;
|
||||
|
||||
polypsink->buffer = NULL;
|
||||
polypsink->buffer_index = 0;
|
||||
|
||||
polypsink->latency = 0;
|
||||
polypsink->counter = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_polypsink_dispose (GObject * object)
|
||||
{
|
||||
GstPolypSink *polypsink = GST_POLYPSINK (object);
|
||||
|
||||
/* gst_object_unparent(GST_OBJECT(polypsink->provided_clock)); */
|
||||
|
||||
|
||||
destroy_context (polypsink);
|
||||
|
||||
if (polypsink->buffer)
|
||||
gst_buffer_unref (polypsink->buffer);
|
||||
|
||||
|
||||
g_free (polypsink->server);
|
||||
g_free (polypsink->sink);
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
|
||||
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; */
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gst_polypsink_factory_init (GstPlugin * plugin)
|
||||
{
|
||||
return gst_element_register (plugin, "polypsink", GST_RANK_NONE,
|
||||
GST_TYPE_POLYPSINK);
|
||||
}
|
||||
|
||||
GType
|
||||
gst_polypsink_get_type (void)
|
||||
{
|
||||
static GType polypsink_type = 0;
|
||||
|
||||
if (!polypsink_type) {
|
||||
|
||||
static const GTypeInfo polypsink_info = {
|
||||
sizeof (GstPolypSinkClass),
|
||||
gst_polypsink_base_init,
|
||||
NULL,
|
||||
gst_polypsink_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstPolypSink),
|
||||
0,
|
||||
gst_polypsink_init,
|
||||
};
|
||||
|
||||
polypsink_type =
|
||||
g_type_register_static (GST_TYPE_ELEMENT, "GstPolypSink",
|
||||
&polypsink_info, 0);
|
||||
}
|
||||
|
||||
return polypsink_type;
|
||||
}
|
59
ext/polyp/polypsink.h
Normal file
59
ext/polyp/polypsink.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef __GST_POLYPSINK_H__
|
||||
#define __GST_POLYPSINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <polyp/polyplib-context.h>
|
||||
#include <polyp/polyplib-stream.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_POLYPSINK \
|
||||
(gst_polypsink_get_type())
|
||||
#define GST_POLYPSINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_POLYPSINK,GstPolypSink))
|
||||
#define GST_POLYPSINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_POLYPSINK,GstPolypSinkClass))
|
||||
#define GST_IS_POLYPSINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_POLYPSINK))
|
||||
#define GST_IS_POLYPSINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_POLYPSINK))
|
||||
|
||||
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;
|
||||
|
||||
int negotiated;
|
||||
|
||||
GstBuffer *buffer;
|
||||
size_t buffer_index;
|
||||
|
||||
size_t counter;
|
||||
pa_usec_t latency;
|
||||
|
||||
gboolean caching;
|
||||
char *cache_id;
|
||||
};
|
||||
|
||||
struct _GstPolypSinkClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_polypsink_get_type(void);
|
||||
gboolean gst_polypsink_factory_init(GstPlugin *plugin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_POLYPSINK_H__ */
|
Loading…
Reference in a new issue