mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
pulse: remove pulseaudiosink helper bin
This is causing us lots of headaches in 0.10 and needs to be done differently and properly in 0.11. playbin or decodebin should reconfigure themselves based on reconfigure events, for example.
This commit is contained in:
parent
2799bcd32e
commit
ff74718616
6 changed files with 16 additions and 1002 deletions
|
@ -9,21 +9,6 @@
|
|||
<package>GStreamer Good Plug-ins git</package>
|
||||
<origin>Unknown package origin</origin>
|
||||
<elements>
|
||||
<element>
|
||||
<name>pulseaudiosink</name>
|
||||
<longname>Bin wrapping pulsesink</longname>
|
||||
<class>Sink/Audio/Bin</class>
|
||||
<description>Correctly handles sink changes when streaming compressed formats to pulsesink</description>
|
||||
<author>Arun Raghavan <arun.raghavan@collabora.co.uk></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>audio/x-raw-int, endianness=(int){ 1234, 4321 }, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-raw-float, endianness=(int){ 1234, 4321 }, width=(int)32, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-raw-int, endianness=(int){ 1234, 4321 }, signed=(boolean)true, width=(int)32, depth=(int)32, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-raw-int, signed=(boolean)false, width=(int)8, depth=(int)8, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-alaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-mulaw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-raw-int, endianness=(int){ 1234, 4321 }, signed=(boolean)true, width=(int)24, depth=(int)24, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-raw-int, endianness=(int){ 1234, 4321 }, signed=(boolean)true, width=(int)32, depth=(int)24, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 32 ]; audio/x-ac3, framed=(boolean)true; audio/x-eac3, framed=(boolean)true; audio/x-dts, framed=(boolean)true, block-size=(int){ 512, 1024, 2048 }; audio/mpeg, mpegversion=(int)1, mpegaudioversion=(int)[ 1, 2 ], parsed=(boolean)true</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
<element>
|
||||
<name>pulsemixer</name>
|
||||
<longname>PulseAudio Mixer</longname>
|
||||
|
@ -64,4 +49,4 @@
|
|||
</pads>
|
||||
</element>
|
||||
</elements>
|
||||
</plugin>
|
||||
</plugin>
|
||||
|
|
|
@ -7,7 +7,6 @@ libgstpulse_la_SOURCES = \
|
|||
pulsemixertrack.c \
|
||||
pulseprobe.c \
|
||||
pulsesink.c \
|
||||
pulseaudiosink.c \
|
||||
pulsesrc.c \
|
||||
pulseutil.c
|
||||
|
||||
|
|
|
@ -49,12 +49,6 @@ plugin_init (GstPlugin * plugin)
|
|||
GST_TYPE_PULSESRC))
|
||||
return FALSE;
|
||||
|
||||
/* FIXME 0.11: this helper bin sink should just go away, reconfiguration
|
||||
* should be handled using reconfigure events */
|
||||
if (!gst_element_register (plugin, "pulseaudiosink", GST_RANK_PRIMARY + 11,
|
||||
GST_TYPE_PULSE_AUDIO_SINK))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_element_register (plugin, "pulsemixer", GST_RANK_NONE,
|
||||
GST_TYPE_PULSEMIXER))
|
||||
return FALSE;
|
||||
|
|
|
@ -1,960 +0,0 @@
|
|||
/*-*- Mode: C; c-basic-offset: 2 -*-*/
|
||||
|
||||
/* GStreamer pulseaudio plugin
|
||||
*
|
||||
* Copyright (c) 2011 Intel Corporation
|
||||
* 2011 Collabora
|
||||
* 2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
|
||||
* 2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* gst-pulse 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-pulse 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-pulse; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-pulseaudiosink
|
||||
* @see_also: pulsesink, pulsesrc, pulsemixer
|
||||
*
|
||||
* This element outputs audio to a
|
||||
* <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink> via
|
||||
* the @pulsesink element. It transparently takes care of passing compressed
|
||||
* format as-is if the sink supports it, decoding if necessary, and changes
|
||||
* to supported formats at runtime.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example pipelines</title>
|
||||
* |[
|
||||
* gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! pulseaudiosink
|
||||
* ]| Decode and play an Ogg/Vorbis file.
|
||||
* |[
|
||||
* gst-launch -v filesrc location=test.mp3 ! mp3parse ! pulseaudiosink stream-properties="props,media.title=test"
|
||||
* ]| Play an MP3 file on a sink that supports decoding directly, plug in a
|
||||
* decoder if/when required.
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/* FIXME 0.11: pulseaudiosink helper bin must die */
|
||||
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
#include <gst/gst-i18n-plugin.h>
|
||||
|
||||
#include <gst/audio/gstaudioiec61937.h>
|
||||
#include "pulsesink.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (pulseaudiosink_debug);
|
||||
#define GST_CAT_DEFAULT (pulseaudiosink_debug)
|
||||
|
||||
#define GST_PULSE_AUDIO_SINK_LOCK(obj) G_STMT_START { \
|
||||
GST_LOG_OBJECT (obj, \
|
||||
"locking from thread %p", \
|
||||
g_thread_self ()); \
|
||||
g_mutex_lock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock); \
|
||||
GST_LOG_OBJECT (obj, \
|
||||
"locked from thread %p", \
|
||||
g_thread_self ()); \
|
||||
} G_STMT_END
|
||||
|
||||
#define GST_PULSE_AUDIO_SINK_UNLOCK(obj) G_STMT_START { \
|
||||
GST_LOG_OBJECT (obj, \
|
||||
"unlocking from thread %p", \
|
||||
g_thread_self ()); \
|
||||
g_mutex_unlock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock); \
|
||||
} G_STMT_END
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstBin parent;
|
||||
GMutex *lock;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstPad *sink_proxypad;
|
||||
GstPadEventFunction sinkpad_old_eventfunc;
|
||||
GstPadEventFunction proxypad_old_eventfunc;
|
||||
|
||||
GstPulseSink *psink;
|
||||
GstElement *dbin;
|
||||
|
||||
GstSegment segment;
|
||||
|
||||
guint event_probe_id;
|
||||
gulong pad_added_id;
|
||||
guint block_probe_id;
|
||||
|
||||
gboolean format_lost;
|
||||
} GstPulseAudioSink;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstBinClass parent_class;
|
||||
guint n_prop_own;
|
||||
guint n_prop_total;
|
||||
} GstPulseAudioSinkClass;
|
||||
|
||||
static void gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_pulse_audio_sink_dispose (GObject * object);
|
||||
static gboolean gst_pulse_audio_sink_src_event (GstPad * pad,
|
||||
GstObject * parent, GstEvent * event);
|
||||
static gboolean gst_pulse_audio_sink_sink_event (GstPad * pad,
|
||||
GstObject * parent, GstEvent * event);
|
||||
static gboolean gst_pulse_audio_sink_sink_query (GstPad * pad,
|
||||
GstObject * parent, GstQuery * query);
|
||||
static gboolean gst_pulse_audio_sink_sink_acceptcaps (GstPulseAudioSink * pbin,
|
||||
GstPad * pad, GstCaps * caps);
|
||||
static GstStateChangeReturn gst_pulse_audio_sink_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
static gboolean gst_pulse_audio_sink_set_caps (GstPulseAudioSink * pbin,
|
||||
GstCaps * caps);
|
||||
|
||||
#define gst_pulse_audio_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstPulseAudioSink, gst_pulse_audio_sink, GST_TYPE_BIN);
|
||||
|
||||
static GstStaticPadTemplate sink_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
|
||||
|
||||
static GParamSpec *
|
||||
param_spec_copy (GParamSpec * spec)
|
||||
{
|
||||
const char *name, *nick, *blurb;
|
||||
GParamFlags flags;
|
||||
|
||||
name = g_param_spec_get_name (spec);
|
||||
nick = g_param_spec_get_nick (spec);
|
||||
blurb = g_param_spec_get_blurb (spec);
|
||||
flags = spec->flags;
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOOLEAN) {
|
||||
return g_param_spec_boolean (name, nick, blurb,
|
||||
G_PARAM_SPEC_BOOLEAN (spec)->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOXED) {
|
||||
return g_param_spec_boxed (name, nick, blurb, spec->value_type, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_CHAR) {
|
||||
GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (spec);
|
||||
return g_param_spec_char (name, nick, blurb, cspec->minimum,
|
||||
cspec->maximum, cspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_DOUBLE) {
|
||||
GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (spec);
|
||||
return g_param_spec_double (name, nick, blurb, dspec->minimum,
|
||||
dspec->maximum, dspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ENUM) {
|
||||
return g_param_spec_enum (name, nick, blurb, spec->value_type,
|
||||
G_PARAM_SPEC_ENUM (spec)->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLAGS) {
|
||||
return g_param_spec_flags (name, nick, blurb, spec->value_type,
|
||||
G_PARAM_SPEC_ENUM (spec)->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLOAT) {
|
||||
GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (spec);
|
||||
return g_param_spec_double (name, nick, blurb, fspec->minimum,
|
||||
fspec->maximum, fspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_GTYPE) {
|
||||
return g_param_spec_gtype (name, nick, blurb,
|
||||
G_PARAM_SPEC_GTYPE (spec)->is_a_type, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT) {
|
||||
GParamSpecInt *ispec = G_PARAM_SPEC_INT (spec);
|
||||
return g_param_spec_int (name, nick, blurb, ispec->minimum,
|
||||
ispec->maximum, ispec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT64) {
|
||||
GParamSpecInt64 *ispec = G_PARAM_SPEC_INT64 (spec);
|
||||
return g_param_spec_int64 (name, nick, blurb, ispec->minimum,
|
||||
ispec->maximum, ispec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_LONG) {
|
||||
GParamSpecLong *lspec = G_PARAM_SPEC_LONG (spec);
|
||||
return g_param_spec_long (name, nick, blurb, lspec->minimum,
|
||||
lspec->maximum, lspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_OBJECT) {
|
||||
return g_param_spec_object (name, nick, blurb, spec->value_type, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_PARAM) {
|
||||
return g_param_spec_param (name, nick, blurb, spec->value_type, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_POINTER) {
|
||||
return g_param_spec_pointer (name, nick, blurb, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_STRING) {
|
||||
return g_param_spec_string (name, nick, blurb,
|
||||
G_PARAM_SPEC_STRING (spec)->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UCHAR) {
|
||||
GParamSpecUChar *cspec = G_PARAM_SPEC_UCHAR (spec);
|
||||
return g_param_spec_uchar (name, nick, blurb, cspec->minimum,
|
||||
cspec->maximum, cspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT) {
|
||||
GParamSpecUInt *ispec = G_PARAM_SPEC_UINT (spec);
|
||||
return g_param_spec_uint (name, nick, blurb, ispec->minimum,
|
||||
ispec->maximum, ispec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT64) {
|
||||
GParamSpecUInt64 *ispec = G_PARAM_SPEC_UINT64 (spec);
|
||||
return g_param_spec_uint64 (name, nick, blurb, ispec->minimum,
|
||||
ispec->maximum, ispec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ULONG) {
|
||||
GParamSpecULong *lspec = G_PARAM_SPEC_ULONG (spec);
|
||||
return g_param_spec_ulong (name, nick, blurb, lspec->minimum,
|
||||
lspec->maximum, lspec->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UNICHAR) {
|
||||
return g_param_spec_unichar (name, nick, blurb,
|
||||
G_PARAM_SPEC_UNICHAR (spec)->default_value, flags);
|
||||
}
|
||||
|
||||
if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_VARIANT) {
|
||||
GParamSpecVariant *vspec = G_PARAM_SPEC_VARIANT (spec);
|
||||
return g_param_spec_variant (name, nick, blurb, vspec->type,
|
||||
vspec->default_value, flags);
|
||||
}
|
||||
|
||||
g_warning ("Unknown param type %ld for '%s'",
|
||||
(long) G_PARAM_SPEC_TYPE (spec), name);
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_class_init (GstPulseAudioSinkClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
GstElementClass *element_class = (GstElementClass *) klass;
|
||||
GstPulseSinkClass *psink_class =
|
||||
GST_PULSESINK_CLASS (g_type_class_ref (GST_TYPE_PULSESINK));
|
||||
GParamSpec **specs;
|
||||
guint n, i, j;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (pulseaudiosink_debug, "pulseaudiosink", 0,
|
||||
"Bin that wraps pulsesink for handling compressed formats");
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
gst_element_class_set_details_simple (element_class,
|
||||
"Bin wrapping pulsesink", "Sink/Audio/Bin",
|
||||
"Correctly handles sink changes when streaming compressed formats to "
|
||||
"pulsesink", "Arun Raghavan <arun.raghavan@collabora.co.uk>");
|
||||
|
||||
gobject_class->get_property = gst_pulse_audio_sink_get_property;
|
||||
gobject_class->set_property = gst_pulse_audio_sink_set_property;
|
||||
gobject_class->dispose = gst_pulse_audio_sink_dispose;
|
||||
element_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_change_state);
|
||||
|
||||
/* Find out how many properties we already have */
|
||||
specs = g_object_class_list_properties (gobject_class, &klass->n_prop_own);
|
||||
g_free (specs);
|
||||
|
||||
/* Proxy pulsesink's properties */
|
||||
specs = g_object_class_list_properties (G_OBJECT_CLASS (psink_class), &n);
|
||||
for (i = 0, j = klass->n_prop_own; i < n; i++) {
|
||||
if (g_object_class_find_property (gobject_class,
|
||||
g_param_spec_get_name (specs[i]))) {
|
||||
/* We already inherited this property from a parent, skip */
|
||||
j--;
|
||||
} else {
|
||||
g_object_class_install_property (gobject_class, i + j + 1,
|
||||
param_spec_copy (specs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
klass->n_prop_total = i + j;
|
||||
|
||||
g_free (specs);
|
||||
g_type_class_unref (psink_class);
|
||||
}
|
||||
|
||||
static GstPad *
|
||||
get_proxypad (GstPad * sinkpad)
|
||||
{
|
||||
GstIterator *iter = NULL;
|
||||
GValue res = { 0 };
|
||||
GstPad *proxypad = NULL;
|
||||
|
||||
iter = gst_pad_iterate_internal_links (sinkpad);
|
||||
if (iter) {
|
||||
if (gst_iterator_next (iter, &res) == GST_ITERATOR_OK) {
|
||||
proxypad = g_value_dup_object (&res);
|
||||
g_value_reset (&res);
|
||||
}
|
||||
gst_iterator_free (iter);
|
||||
}
|
||||
|
||||
return proxypad;
|
||||
}
|
||||
|
||||
static void
|
||||
post_missing_element_message (GstPulseAudioSink * pbin, const gchar * name)
|
||||
{
|
||||
GstMessage *msg;
|
||||
|
||||
msg = gst_missing_element_message_new (GST_ELEMENT_CAST (pbin), name);
|
||||
gst_element_post_message (GST_ELEMENT_CAST (pbin), msg);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_cb (GObject * selector, GParamSpec * pspec, GstPulseAudioSink * pbin)
|
||||
{
|
||||
g_object_notify (G_OBJECT (pbin), g_param_spec_get_name (pspec));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_init (GstPulseAudioSink * pbin)
|
||||
{
|
||||
GstPulseAudioSinkClass *klass =
|
||||
GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (pbin));
|
||||
GstPad *pad = NULL;
|
||||
GParamSpec **specs;
|
||||
GString *prop;
|
||||
guint i;
|
||||
|
||||
pbin->lock = g_mutex_new ();
|
||||
|
||||
gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
|
||||
|
||||
pbin->psink = GST_PULSESINK (gst_element_factory_make ("pulsesink",
|
||||
"pulseaudiosink-sink"));
|
||||
g_assert (pbin->psink != NULL);
|
||||
|
||||
if (!gst_bin_add (GST_BIN (pbin), GST_ELEMENT (pbin->psink))) {
|
||||
GST_ERROR_OBJECT (pbin, "Failed to add pulsesink to bin");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
|
||||
pbin->sinkpad = gst_ghost_pad_new_from_template ("sink", pad,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
pbin->sinkpad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sinkpad);
|
||||
gst_pad_set_event_function (pbin->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_event));
|
||||
gst_pad_set_query_function (pbin->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_query));
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (pbin), pbin->sinkpad);
|
||||
|
||||
if (!(pbin->sink_proxypad = get_proxypad (pbin->sinkpad)))
|
||||
GST_ERROR_OBJECT (pbin, "Failed to get proxypad of srcpad");
|
||||
else {
|
||||
pbin->proxypad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sink_proxypad);
|
||||
gst_pad_set_event_function (pbin->sink_proxypad,
|
||||
GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_src_event));
|
||||
}
|
||||
|
||||
/* Now proxy all the notify::* signals */
|
||||
specs = g_object_class_list_properties (G_OBJECT_CLASS (klass), &i);
|
||||
prop = g_string_sized_new (30);
|
||||
|
||||
for (i--; i >= klass->n_prop_own; i--) {
|
||||
g_string_printf (prop, "notify::%s", g_param_spec_get_name (specs[i]));
|
||||
g_signal_connect (pbin->psink, prop->str, G_CALLBACK (notify_cb), pbin);
|
||||
}
|
||||
|
||||
g_string_free (prop, TRUE);
|
||||
g_free (specs);
|
||||
|
||||
pbin->format_lost = FALSE;
|
||||
|
||||
out:
|
||||
if (pad)
|
||||
gst_object_unref (pad);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
if (pbin->psink)
|
||||
gst_object_unref (pbin->psink);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
|
||||
GstPulseAudioSinkClass *klass =
|
||||
GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
|
||||
|
||||
g_return_if_fail (prop_id <= klass->n_prop_total);
|
||||
|
||||
g_object_set_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
|
||||
value);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
|
||||
GstPulseAudioSinkClass *klass =
|
||||
GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
|
||||
|
||||
g_return_if_fail (prop_id <= klass->n_prop_total);
|
||||
|
||||
g_object_get_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
|
||||
value);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_free_dbin (GstPulseAudioSink * pbin)
|
||||
{
|
||||
g_signal_handler_disconnect (pbin->dbin, pbin->pad_added_id);
|
||||
gst_element_set_state (pbin->dbin, GST_STATE_NULL);
|
||||
|
||||
gst_bin_remove (GST_BIN (pbin), pbin->dbin);
|
||||
|
||||
pbin->dbin = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_pulse_audio_sink_dispose (GObject * object)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
|
||||
|
||||
if (pbin->lock) {
|
||||
g_mutex_free (pbin->lock);
|
||||
pbin->lock = NULL;
|
||||
}
|
||||
|
||||
if (pbin->sink_proxypad) {
|
||||
gst_object_unref (pbin->sink_proxypad);
|
||||
pbin->sink_proxypad = NULL;
|
||||
}
|
||||
|
||||
if (pbin->dbin) {
|
||||
g_signal_handler_disconnect (pbin->dbin, pbin->pad_added_id);
|
||||
pbin->dbin = NULL;
|
||||
}
|
||||
|
||||
pbin->sinkpad = NULL;
|
||||
pbin->psink = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_update_sinkpad (GstPulseAudioSink * pbin, GstPad * sinkpad)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (pbin->sinkpad), sinkpad);
|
||||
|
||||
if (!ret)
|
||||
GST_WARNING_OBJECT (pbin, "Could not update ghostpad target");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
distribute_running_time (GstElement * element, const GstSegment * segment)
|
||||
{
|
||||
GstEvent *event;
|
||||
GstPad *pad;
|
||||
|
||||
pad = gst_element_get_static_pad (element, "sink");
|
||||
|
||||
/* FIXME: Some decoders collect newsegments and send them out at once, making
|
||||
* them lose accumulator events (and thus making dbin_event_probe() hard to
|
||||
* do right if we're sending these as well. We can get away with not sending
|
||||
* these at the moment, but this should be fixed! */
|
||||
#if 0
|
||||
if (segment->accum) {
|
||||
event = gst_event_new_new_segment_full (FALSE, segment->rate,
|
||||
segment->applied_rate, segment->format, 0, segment->accum, 0);
|
||||
gst_pad_send_event (pad, event);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO review this copy, see if it can be avoided */
|
||||
event = gst_event_new_segment (gst_segment_copy (segment));
|
||||
gst_pad_send_event (pad, event);
|
||||
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
|
||||
static GstPadProbeReturn
|
||||
dbin_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer data)
|
||||
{
|
||||
GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
|
||||
GST_DEBUG_OBJECT (pbin, "Got newsegment - dropping");
|
||||
pbin->event_probe_id = 0;
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
}
|
||||
|
||||
return GST_PAD_PROBE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
pad_added_cb (GstElement * dbin, GstPad * pad, gpointer * data)
|
||||
{
|
||||
GstPulseAudioSink *pbin;
|
||||
GstPad *sinkpad = NULL;
|
||||
|
||||
pbin = GST_PULSE_AUDIO_SINK (data);
|
||||
sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
|
||||
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
|
||||
GST_ERROR_OBJECT (pbin, "Failed to link decodebin to pulsesink");
|
||||
else
|
||||
GST_DEBUG_OBJECT (pbin, "Linked new pad to pulsesink");
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
gst_object_unref (sinkpad);
|
||||
}
|
||||
|
||||
/* Called with pbin lock held */
|
||||
static void
|
||||
gst_pulse_audio_sink_add_dbin (GstPulseAudioSink * pbin)
|
||||
{
|
||||
GstPad *sinkpad = NULL;
|
||||
|
||||
g_assert (pbin->dbin == NULL);
|
||||
|
||||
pbin->dbin = gst_element_factory_make ("decodebin", "pulseaudiosink-dbin");
|
||||
|
||||
if (!pbin->dbin) {
|
||||
post_missing_element_message (pbin, "decodebin");
|
||||
GST_ELEMENT_WARNING (pbin, CORE, MISSING_PLUGIN,
|
||||
(_("Missing element '%s' - check your GStreamer installation."),
|
||||
"decodebin"), ("audio playback might fail"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!gst_bin_add (GST_BIN (pbin), pbin->dbin)) {
|
||||
GST_ERROR_OBJECT (pbin, "Failed to add decodebin to bin");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pbin->pad_added_id = g_signal_connect (pbin->dbin, "pad-added",
|
||||
G_CALLBACK (pad_added_cb), pbin);
|
||||
|
||||
if (!gst_element_sync_state_with_parent (pbin->dbin)) {
|
||||
GST_ERROR_OBJECT (pbin, "Failed to set decodebin to parent state");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Trap the newsegment events that we feed the decodebin and discard them */
|
||||
sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
|
||||
|
||||
if (pbin->event_probe_id == 0)
|
||||
pbin->event_probe_id =
|
||||
gst_pad_add_probe (sinkpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
|
||||
dbin_event_probe, gst_object_ref (pbin),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
|
||||
gst_object_unref (sinkpad);
|
||||
sinkpad = NULL;
|
||||
|
||||
GST_DEBUG_OBJECT (pbin, "Distributing running time to decodebin");
|
||||
distribute_running_time (pbin->dbin, &pbin->segment);
|
||||
|
||||
sinkpad = gst_element_get_static_pad (pbin->dbin, "sink");
|
||||
|
||||
gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
|
||||
|
||||
out:
|
||||
if (sinkpad)
|
||||
gst_object_unref (sinkpad);
|
||||
}
|
||||
|
||||
static void
|
||||
update_eac3_alignment (GstPulseAudioSink * pbin)
|
||||
{
|
||||
GstCaps *caps = gst_pad_peer_query_caps (pbin->sinkpad, NULL);
|
||||
GstStructure *st;
|
||||
|
||||
if (!caps)
|
||||
return;
|
||||
|
||||
st = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
|
||||
GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
|
||||
"alignment", G_TYPE_STRING, pbin->dbin ? "frame" : "iec61937", NULL);
|
||||
|
||||
if (!gst_pad_push_event (pbin->sinkpad,
|
||||
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
|
||||
GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
|
||||
}
|
||||
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
|
||||
static GstPadProbeReturn
|
||||
proxypad_blocked_cb (GstPad * pad, GstPadProbeInfo * info, gpointer data)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
|
||||
GstCaps *caps;
|
||||
GstPad *sinkpad = NULL;
|
||||
|
||||
GST_DEBUG_OBJECT (pbin, "blocked");
|
||||
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
|
||||
if (!pbin->format_lost) {
|
||||
sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
|
||||
|
||||
if (gst_pad_has_current_caps (pbin->sinkpad)) {
|
||||
/* See if we already got caps on our sinkpad */
|
||||
caps = gst_pad_get_current_caps (pbin->sinkpad);
|
||||
} else {
|
||||
/* We haven't, so get caps from upstream */
|
||||
caps = gst_pad_query_caps (pad, NULL);
|
||||
}
|
||||
|
||||
if (gst_pad_query_accept_caps (sinkpad, caps)) {
|
||||
if (pbin->dbin) {
|
||||
GST_DEBUG_OBJECT (pbin, "Removing decodebin");
|
||||
gst_pulse_audio_sink_free_dbin (pbin);
|
||||
gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (pbin, "Doing nothing");
|
||||
gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
|
||||
}
|
||||
|
||||
gst_caps_unref (caps);
|
||||
gst_object_unref (sinkpad);
|
||||
goto done;
|
||||
}
|
||||
/* pulsesink doesn't accept the incoming caps, so add a decodebin
|
||||
* (potentially after removing the existing once, since decodebin can't
|
||||
* renegotiate). */
|
||||
} else {
|
||||
/* Format lost, proceed to try plugging a decodebin */
|
||||
pbin->format_lost = FALSE;
|
||||
}
|
||||
|
||||
if (pbin->dbin != NULL) {
|
||||
/* decodebin doesn't support reconfiguration, so throw this one away and
|
||||
* create a new one. */
|
||||
gst_pulse_audio_sink_free_dbin (pbin);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (pbin, "Adding decodebin");
|
||||
gst_pulse_audio_sink_add_dbin (pbin);
|
||||
|
||||
done:
|
||||
update_eac3_alignment (pbin);
|
||||
|
||||
pbin->block_probe_id = 0;
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_src_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event)
|
||||
{
|
||||
GstPulseAudioSink *pbin = NULL;
|
||||
GstPad *ghostpad = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
ghostpad = GST_PAD_CAST (parent);
|
||||
if (G_UNLIKELY (!ghostpad)) {
|
||||
GST_WARNING_OBJECT (pad, "Could not get ghostpad");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (ghostpad));
|
||||
if (G_UNLIKELY (!pbin)) {
|
||||
GST_WARNING_OBJECT (pad, "Could not get pulseaudiosink");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) &&
|
||||
(gst_event_has_name (event, "pulse-format-lost") ||
|
||||
gst_event_has_name (event, "pulse-sink-changed"))) {
|
||||
g_return_val_if_fail (pad->mode != GST_PAD_MODE_PULL, FALSE);
|
||||
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
if (gst_event_has_name (event, "pulse-format-lost"))
|
||||
pbin->format_lost = TRUE;
|
||||
|
||||
if (pbin->block_probe_id == 0)
|
||||
pbin->block_probe_id =
|
||||
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
|
||||
proxypad_blocked_cb, gst_object_ref (pbin),
|
||||
(GDestroyNotify) gst_object_unref);
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
ret = TRUE;
|
||||
} else if (pbin->proxypad_old_eventfunc) {
|
||||
ret = pbin->proxypad_old_eventfunc (pad, parent, event);
|
||||
event = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
if (pbin)
|
||||
gst_object_unref (pbin);
|
||||
if (event)
|
||||
gst_event_unref (event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_sink_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (parent);
|
||||
gboolean ret;
|
||||
gboolean forward = TRUE;
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
gst_event_parse_caps (event, &caps);
|
||||
ret = gst_pulse_audio_sink_set_caps (pbin, caps);
|
||||
forward = FALSE;
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
const GstSegment *segment = NULL;
|
||||
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
gst_event_parse_segment (event, &segment);
|
||||
|
||||
GST_DEBUG_OBJECT (pbin, "newsegment: %" GST_SEGMENT_FORMAT, segment);
|
||||
|
||||
if (segment->format == GST_FORMAT_TIME) {
|
||||
/* Store the values for feeding to sub-elements */
|
||||
gst_segment_copy_into (segment, &pbin->segment);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (pbin, "Got a non-TIME format segment");
|
||||
gst_segment_init (&pbin->segment, GST_FORMAT_TIME);
|
||||
}
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GST_EVENT_FLUSH_STOP:
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (forward)
|
||||
ret = pbin->sinkpad_old_eventfunc (pad, parent, event);
|
||||
else
|
||||
gst_event_unref (event);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The bin's acceptcaps should be exactly equivalent to a pulsesink that is
|
||||
* connected to a sink that supports all the formats in template caps. This
|
||||
* means that upstream will have to have everything possibly upto a parser
|
||||
* plugged and we plugin a decoder whenever required. */
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_sink_acceptcaps (GstPulseAudioSink * pbin, GstPad * pad,
|
||||
GstCaps * caps)
|
||||
{
|
||||
GstAudioRingBufferSpec spec = { 0 };
|
||||
const GstStructure *st;
|
||||
GstCaps *pad_caps = NULL;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
pad_caps = gst_pad_query_caps (pad, caps);
|
||||
if (!pad_caps || gst_caps_is_empty (pad_caps))
|
||||
goto out;
|
||||
|
||||
/* If we've not got fixed caps, creating a stream might fail, so let's just
|
||||
* return from here with default acceptcaps behaviour */
|
||||
if (!gst_caps_is_fixed (caps))
|
||||
goto out;
|
||||
|
||||
spec.latency_time = GST_AUDIO_BASE_SINK (pbin->psink)->latency_time;
|
||||
if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
|
||||
goto out;
|
||||
|
||||
/* Make sure non-raw input is framed (one frame per buffer) and can be
|
||||
* payloaded */
|
||||
st = gst_caps_get_structure (caps, 0);
|
||||
|
||||
if (!g_str_has_prefix (gst_structure_get_name (st), "audio/x-raw")) {
|
||||
gboolean framed = FALSE, parsed = FALSE;
|
||||
|
||||
gst_structure_get_boolean (st, "framed", &framed);
|
||||
gst_structure_get_boolean (st, "parsed", &parsed);
|
||||
if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (pad_caps)
|
||||
gst_caps_unref (pad_caps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_sink_query (GstPad * pad, GstObject * parent,
|
||||
GstQuery * query)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (parent);
|
||||
gboolean ret = FALSE;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_ACCEPT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
|
||||
gst_query_parse_accept_caps (query, &caps);
|
||||
ret = gst_pulse_audio_sink_sink_acceptcaps (pbin, pad, caps);
|
||||
gst_query_set_accept_caps_result (query, ret);
|
||||
ret = TRUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = gst_pad_query_default (pad, parent, query);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_pulse_audio_sink_set_caps (GstPulseAudioSink * pbin, GstCaps * caps)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
|
||||
GST_DEBUG_OBJECT (pbin, "got caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (gst_pad_has_current_caps (pbin->sinkpad)) {
|
||||
GstCaps *current;
|
||||
/* See if we already got caps on our sinkpad */
|
||||
current = gst_pad_get_current_caps (pbin->sinkpad);
|
||||
ret = gst_caps_is_equal (caps, current);
|
||||
gst_caps_unref (current);
|
||||
if (ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pbin->block_probe_id == 0)
|
||||
pbin->block_probe_id =
|
||||
gst_pad_add_probe (pbin->sink_proxypad,
|
||||
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, proxypad_blocked_cb,
|
||||
gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
|
||||
|
||||
done:
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_pulse_audio_sink_change_state (GstElement * element,
|
||||
GstStateChange transition)
|
||||
{
|
||||
GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (element);
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
|
||||
/* Nothing to do for upward transitions */
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
if (pbin->block_probe_id) {
|
||||
gst_pad_remove_probe (pbin->sink_proxypad, pbin->block_probe_id);
|
||||
pbin->block_probe_id = 0;
|
||||
}
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
if (ret != GST_STATE_CHANGE_SUCCESS) {
|
||||
GST_DEBUG_OBJECT (pbin, "Base class returned %d on state change", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
GST_PULSE_AUDIO_SINK_LOCK (pbin);
|
||||
gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
|
||||
|
||||
if (pbin->dbin) {
|
||||
GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink),
|
||||
"sink");
|
||||
|
||||
gst_pulse_audio_sink_free_dbin (pbin);
|
||||
gst_pulse_audio_sink_update_sinkpad (pbin, pad);
|
||||
|
||||
gst_object_unref (pad);
|
||||
|
||||
}
|
||||
GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
|
@ -426,6 +426,8 @@ gst_pulsering_context_subscribe_cb (pa_context * c,
|
|||
|
||||
GST_INFO_OBJECT (psink, "emitting sink-changed");
|
||||
|
||||
/* FIXME: send reconfigure event instead and let decodebin/playbin
|
||||
* handle that. Also take care of ac3 alignment. See "pulse-format-lost" */
|
||||
renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||
gst_structure_new_empty ("pulse-sink-changed"));
|
||||
|
||||
|
@ -742,9 +744,22 @@ gst_pulsering_stream_event_cb (pa_stream * p, const char *name,
|
|||
g_free (psink->device);
|
||||
psink->device = g_strdup (pa_proplist_gets (pl, "device"));
|
||||
|
||||
/* FIXME: send reconfigure event instead and let decodebin/playbin
|
||||
* handle that. Also take care of ac3 alignment */
|
||||
renego = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||
gst_structure_new_empty ("pulse-format-lost"));
|
||||
|
||||
#if 0
|
||||
if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
|
||||
GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
|
||||
"alignment", G_TYPE_STRING, pbin->dbin ? "frame" : "iec61937", NULL);
|
||||
|
||||
if (!gst_pad_push_event (pbin->sinkpad,
|
||||
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
|
||||
GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego)) {
|
||||
/* Nobody handled the format change - emit an error */
|
||||
GST_ELEMENT_ERROR (psink, STREAM, FORMAT, ("Sink format changed"),
|
||||
|
@ -1938,8 +1953,6 @@ done:
|
|||
pa_threaded_mainloop_signal (mainloop, 0);
|
||||
}
|
||||
|
||||
/* NOTE: If you're making changes here, see if pulseaudiosink acceptcaps also
|
||||
* needs to be changed accordingly. */
|
||||
static gboolean
|
||||
gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps)
|
||||
{
|
||||
|
|
|
@ -121,23 +121,6 @@ GType gst_pulsesink_get_type (void);
|
|||
_PULSE_SINK_CAPS_COMMON \
|
||||
_PULSE_SINK_CAPS_1_0
|
||||
|
||||
/* FIXME 0.11: pulseaudiosink helper bin must die */
|
||||
|
||||
#define GST_TYPE_PULSE_AUDIO_SINK \
|
||||
(gst_pulse_audio_sink_get_type())
|
||||
#define GST_PULSE_AUDIO_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PULSE_AUDIO_SINK,GstPulseAudioSink))
|
||||
#define GST_PULSE_AUDIO_SINK_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PULSE_AUDIO_SINK,GstPulseAudioSinkClass))
|
||||
#define GST_IS_PULSE_AUDIO_SINK(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PULSE_AUDIO_SINK))
|
||||
#define GST_IS_PULSE_AUDIO_SINK_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PULSE_AUDIO_SINK))
|
||||
#define GST_PULSE_AUDIO_SINK_CAST(obj) \
|
||||
((GstPulseAudioSink *)(obj))
|
||||
|
||||
GType gst_pulse_audio_sink_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_PULSESINK_H__ */
|
||||
|
|
Loading…
Reference in a new issue