mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
Re-factor the gconfaudiosink into a "GstSwitchSink" base class and a child that implements the GConf key monitoring. ...
Original commit message from CVS: * ext/gconf/Makefile.am: * ext/gconf/gconf.c: (gst_gconf_get_string), (gst_gconf_get_key_for_sink_profile), (gst_gconf_set_string), (gst_gconf_render_bin_with_default): * ext/gconf/gconf.h: * ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init), (gst_gconf_audio_sink_reset), (gst_gconf_audio_sink_init), (gst_gconf_audio_sink_dispose), (do_change_child), (gst_gconf_switch_profile), (gst_gconf_audio_sink_set_property), (cb_change_child), (gst_gconf_audio_sink_change_state): * ext/gconf/gstgconfaudiosink.h: * ext/gconf/gstswitchsink.c: (gst_switch_sink_base_init), (gst_switch_sink_class_init), (gst_switch_sink_reset), (gst_switch_sink_init), (gst_switch_sink_dispose), (gst_switch_commit_new_kid), (gst_switch_sink_set_child), (gst_switch_sink_set_property), (gst_switch_sink_handle_event), (gst_switch_sink_get_property), (gst_switch_sink_change_state): * ext/gconf/gstswitchsink.h: * gst/autodetect/gstautoaudiosink.c: (gst_auto_audio_sink_class_init), (gst_auto_audio_sink_dispose), (gst_auto_audio_sink_clear_kid), (gst_auto_audio_sink_reset), (gst_auto_audio_sink_detect): * gst/autodetect/gstautovideosink.c: (gst_auto_video_sink_class_init), (gst_auto_video_sink_dispose), (gst_auto_video_sink_clear_kid), (gst_auto_video_sink_reset), (gst_auto_video_sink_detect): Re-factor the gconfaudiosink into a "GstSwitchSink" base class and a child that implements the GConf key monitoring. The end goal of this is an audio sink that can be changed on the fly, but at the moment it still only changes on the next READY transition.
This commit is contained in:
parent
5116ff603e
commit
b1aa8fef18
10 changed files with 534 additions and 157 deletions
33
ChangeLog
33
ChangeLog
|
@ -1,3 +1,36 @@
|
||||||
|
2007-02-13 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
|
* ext/gconf/Makefile.am:
|
||||||
|
* ext/gconf/gconf.c: (gst_gconf_get_string),
|
||||||
|
(gst_gconf_get_key_for_sink_profile), (gst_gconf_set_string),
|
||||||
|
(gst_gconf_render_bin_with_default):
|
||||||
|
* ext/gconf/gconf.h:
|
||||||
|
* ext/gconf/gstgconfaudiosink.c: (gst_gconf_audio_sink_base_init),
|
||||||
|
(gst_gconf_audio_sink_reset), (gst_gconf_audio_sink_init),
|
||||||
|
(gst_gconf_audio_sink_dispose), (do_change_child),
|
||||||
|
(gst_gconf_switch_profile), (gst_gconf_audio_sink_set_property),
|
||||||
|
(cb_change_child), (gst_gconf_audio_sink_change_state):
|
||||||
|
* ext/gconf/gstgconfaudiosink.h:
|
||||||
|
* ext/gconf/gstswitchsink.c: (gst_switch_sink_base_init),
|
||||||
|
(gst_switch_sink_class_init), (gst_switch_sink_reset),
|
||||||
|
(gst_switch_sink_init), (gst_switch_sink_dispose),
|
||||||
|
(gst_switch_commit_new_kid), (gst_switch_sink_set_child),
|
||||||
|
(gst_switch_sink_set_property), (gst_switch_sink_handle_event),
|
||||||
|
(gst_switch_sink_get_property), (gst_switch_sink_change_state):
|
||||||
|
* ext/gconf/gstswitchsink.h:
|
||||||
|
* gst/autodetect/gstautoaudiosink.c:
|
||||||
|
(gst_auto_audio_sink_class_init), (gst_auto_audio_sink_dispose),
|
||||||
|
(gst_auto_audio_sink_clear_kid), (gst_auto_audio_sink_reset),
|
||||||
|
(gst_auto_audio_sink_detect):
|
||||||
|
* gst/autodetect/gstautovideosink.c:
|
||||||
|
(gst_auto_video_sink_class_init), (gst_auto_video_sink_dispose),
|
||||||
|
(gst_auto_video_sink_clear_kid), (gst_auto_video_sink_reset),
|
||||||
|
(gst_auto_video_sink_detect):
|
||||||
|
Re-factor the gconfaudiosink into a "GstSwitchSink" base class
|
||||||
|
and a child that implements the GConf key monitoring. The end goal of
|
||||||
|
this is an audio sink that can be changed on the fly, but at the
|
||||||
|
moment it still only changes on the next READY transition.
|
||||||
|
|
||||||
2007-02-13 Stefan Kost <ensonic@users.sf.net>
|
2007-02-13 Stefan Kost <ensonic@users.sf.net>
|
||||||
|
|
||||||
* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
|
* gst/avi/gstavidemux.c: (gst_avi_demux_handle_src_query),
|
||||||
|
|
|
@ -6,6 +6,7 @@ libgstgconfelements_la_SOURCES = \
|
||||||
gstgconfelements.c \
|
gstgconfelements.c \
|
||||||
gstgconfvideosink.c \
|
gstgconfvideosink.c \
|
||||||
gstgconfvideosrc.c \
|
gstgconfvideosrc.c \
|
||||||
|
gstswitchsink.c \
|
||||||
gconf.c
|
gconf.c
|
||||||
|
|
||||||
DIR_CFLAGS = -DGST_GCONF_DIR=\"/system/gstreamer/@GST_MAJORMINOR@\"
|
DIR_CFLAGS = -DGST_GCONF_DIR=\"/system/gstreamer/@GST_MAJORMINOR@\"
|
||||||
|
@ -19,4 +20,5 @@ noinst_HEADERS = \
|
||||||
gstgconfelements.h \
|
gstgconfelements.h \
|
||||||
gstgconfvideosink.h \
|
gstgconfvideosink.h \
|
||||||
gstgconfvideosrc.h \
|
gstgconfvideosrc.h \
|
||||||
|
gstswitchsink.h \
|
||||||
gconf.h
|
gconf.h
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
|
* nf_get_default_audio_sink
|
||||||
* Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
|
* Copyright (C) <2002> Thomas Vander Stichele <thomas@apestaart.org>
|
||||||
* Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
|
* Copyright (C) <2006> Jürg Billeter <j@bitron.ch>
|
||||||
*
|
*
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#include "gconf.h"
|
#include "gconf.h"
|
||||||
#include "gstgconfelements.h" /* for debug category */
|
#include "gstgconfelements.h" /* for debug category */
|
||||||
|
|
||||||
|
@ -63,8 +66,12 @@ gst_gconf_get_string (const gchar * key)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gchar *value = NULL;
|
gchar *value = NULL;
|
||||||
gchar *full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
|
gchar *full_key;
|
||||||
|
|
||||||
|
if (!g_str_has_prefix (key, GST_GCONF_DIR))
|
||||||
|
full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
|
||||||
|
else
|
||||||
|
full_key = g_strdup (key);
|
||||||
|
|
||||||
value = gconf_client_get_string (gst_gconf_get_client (), full_key, &error);
|
value = gconf_client_get_string (gst_gconf_get_client (), full_key, &error);
|
||||||
g_free (full_key);
|
g_free (full_key);
|
||||||
|
@ -79,20 +86,20 @@ gst_gconf_get_string (const gchar * key)
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
const gchar *
|
||||||
gst_gconf_get_key_for_sink_profile (guint profile)
|
gst_gconf_get_key_for_sink_profile (GstGConfProfile profile)
|
||||||
{
|
{
|
||||||
switch (profile) {
|
switch (profile) {
|
||||||
case GCONF_PROFILE_SOUNDS:
|
case GCONF_PROFILE_SOUNDS:
|
||||||
return GST_GCONF_AUDIOSINK_KEY;
|
return GST_GCONF_DIR "/" GST_GCONF_AUDIOSINK_KEY;
|
||||||
case GCONF_PROFILE_MUSIC:
|
case GCONF_PROFILE_MUSIC:
|
||||||
return GST_GCONF_MUSIC_AUDIOSINK_KEY;
|
return GST_GCONF_DIR "/" GST_GCONF_MUSIC_AUDIOSINK_KEY;
|
||||||
case GCONF_PROFILE_CHAT:
|
case GCONF_PROFILE_CHAT:
|
||||||
return GST_GCONF_CHAT_AUDIOSINK_KEY;
|
return GST_GCONF_DIR "/" GST_GCONF_CHAT_AUDIOSINK_KEY;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_return_val_if_reached (GST_GCONF_AUDIOSINK_KEY);
|
g_return_val_if_reached (GST_GCONF_DIR "/" GST_GCONF_AUDIOSINK_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +113,12 @@ void
|
||||||
gst_gconf_set_string (const gchar * key, const gchar * value)
|
gst_gconf_set_string (const gchar * key, const gchar * value)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gchar *full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
|
gchar *full_key;
|
||||||
|
|
||||||
|
if (!g_str_has_prefix (key, GST_GCONF_DIR))
|
||||||
|
full_key = g_strdup_printf ("%s/%s", GST_GCONF_DIR, key);
|
||||||
|
else
|
||||||
|
full_key = g_strdup (key);
|
||||||
|
|
||||||
gconf_client_set_string (gst_gconf_get_client (), full_key, value, &error);
|
gconf_client_set_string (gst_gconf_get_client (), full_key, value, &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -149,27 +161,25 @@ gst_gconf_render_bin_from_key (const gchar * key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_gconf_get_default_audio_sink:
|
* gst_gconf_render_bin_with_default:
|
||||||
* @profile: the appropriate application profile.
|
* @bin: a #gchar string corresponding to pipeline to construct.
|
||||||
|
* @default: a pipeline description to use as default if the GConf key
|
||||||
|
* pipeline fails to construct.
|
||||||
*
|
*
|
||||||
* Render audio output bin from GStreamer GConf key : "default/audiosink".
|
* Render bin from GConf key @key using @default as a fallback.
|
||||||
* If key is invalid, the default audio sink for the platform is used
|
|
||||||
* (typically osssink or sunaudiosink).
|
|
||||||
*
|
*
|
||||||
* Returns: a #GstElement containing the audio output bin, or NULL if
|
* Returns: a #GstElement containing the rendered bin.
|
||||||
* everything failed.
|
|
||||||
*/
|
*/
|
||||||
GstElement *
|
GstElement *
|
||||||
gst_gconf_get_default_audio_sink (int profile)
|
gst_gconf_render_bin_with_default (const gchar * bin,
|
||||||
|
const gchar * default_sink)
|
||||||
{
|
{
|
||||||
GstElement *ret;
|
GstElement *ret;
|
||||||
const gchar *key;
|
|
||||||
|
|
||||||
key = gst_gconf_get_key_for_sink_profile (profile);
|
ret = gst_element_factory_make (bin, NULL);
|
||||||
ret = gst_gconf_render_bin_from_key (key);
|
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = gst_element_factory_make (DEFAULT_AUDIOSINK, NULL);
|
ret = gst_element_factory_make (default_sink, NULL);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
g_warning ("No GConf default audio sink key and %s doesn't work",
|
g_warning ("No GConf default audio sink key and %s doesn't work",
|
||||||
|
|
|
@ -37,12 +37,13 @@ G_BEGIN_DECLS
|
||||||
#define GST_GCONF_VIDEOSRC_KEY "default/videosrc"
|
#define GST_GCONF_VIDEOSRC_KEY "default/videosrc"
|
||||||
#define GST_GCONF_VIDEOSINK_KEY "default/videosink"
|
#define GST_GCONF_VIDEOSINK_KEY "default/videosink"
|
||||||
|
|
||||||
enum
|
typedef enum
|
||||||
{
|
{
|
||||||
GCONF_PROFILE_SOUNDS,
|
GCONF_PROFILE_SOUNDS,
|
||||||
GCONF_PROFILE_MUSIC,
|
GCONF_PROFILE_MUSIC,
|
||||||
GCONF_PROFILE_CHAT
|
GCONF_PROFILE_CHAT,
|
||||||
};
|
GCONF_PROFILE_NONE /* Internal value only */
|
||||||
|
} GstGConfProfile;
|
||||||
|
|
||||||
gchar * gst_gconf_get_string (const gchar *key);
|
gchar * gst_gconf_get_string (const gchar *key);
|
||||||
void gst_gconf_set_string (const gchar *key,
|
void gst_gconf_set_string (const gchar *key,
|
||||||
|
@ -51,6 +52,8 @@ void gst_gconf_set_string (const gchar *key,
|
||||||
const gchar * gst_gconf_get_key_for_sink_profile (guint profile);
|
const gchar * gst_gconf_get_key_for_sink_profile (guint profile);
|
||||||
|
|
||||||
GstElement * gst_gconf_render_bin_from_key (const gchar *key);
|
GstElement * gst_gconf_render_bin_from_key (const gchar *key);
|
||||||
|
GstElement * gst_gconf_render_bin_with_default (const gchar *bin,
|
||||||
|
const gchar *default_sink);
|
||||||
|
|
||||||
GstElement * gst_gconf_get_default_video_sink (void);
|
GstElement * gst_gconf_get_default_video_sink (void);
|
||||||
GstElement * gst_gconf_get_default_audio_sink (int profile);
|
GstElement * gst_gconf_get_default_audio_sink (int profile);
|
||||||
|
|
|
@ -28,11 +28,13 @@
|
||||||
#include "gstgconfaudiosink.h"
|
#include "gstgconfaudiosink.h"
|
||||||
|
|
||||||
static void gst_gconf_audio_sink_dispose (GObject * object);
|
static void gst_gconf_audio_sink_dispose (GObject * object);
|
||||||
static void cb_toggle_element (GConfClient * client,
|
static void cb_change_child (GConfClient * client,
|
||||||
guint connection_id, GConfEntry * entry, gpointer data);
|
guint connection_id, GConfEntry * entry, gpointer data);
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_gconf_audio_sink_change_state (GstElement * element,
|
gst_gconf_audio_sink_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
static void gst_gconf_switch_profile (GstGConfAudioSink * sink,
|
||||||
|
GstGConfProfile profile);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -40,7 +42,8 @@ enum
|
||||||
PROP_PROFILE
|
PROP_PROFILE
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_BOILERPLATE (GstGConfAudioSink, gst_gconf_audio_sink, GstBin, GST_TYPE_BIN);
|
GST_BOILERPLATE (GstGConfAudioSink, gst_gconf_audio_sink, GstSwitchSink,
|
||||||
|
GST_TYPE_SWITCH_SINK);
|
||||||
|
|
||||||
static void gst_gconf_audio_sink_set_property (GObject * object, guint prop_id,
|
static void gst_gconf_audio_sink_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec);
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
@ -55,14 +58,8 @@ gst_gconf_audio_sink_base_init (gpointer klass)
|
||||||
GST_ELEMENT_DETAILS ("GConf audio sink",
|
GST_ELEMENT_DETAILS ("GConf audio sink",
|
||||||
"Sink/Audio",
|
"Sink/Audio",
|
||||||
"Audio sink embedding the GConf-settings for audio output",
|
"Audio sink embedding the GConf-settings for audio output",
|
||||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
|
"Ronald Bultje <rbultje@ronald.bitfreak.net>\n"
|
||||||
GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
"Jan Schmidt <thaytan@mad.scientist.com>");
|
||||||
GST_PAD_SINK,
|
|
||||||
GST_PAD_ALWAYS,
|
|
||||||
GST_STATIC_CAPS_ANY);
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (eklass,
|
|
||||||
gst_static_pad_template_get (&sink_template));
|
|
||||||
gst_element_class_set_details (eklass, &gst_gconf_audio_sink_details);
|
gst_element_class_set_details (eklass, &gst_gconf_audio_sink_details);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,68 +98,28 @@ gst_gconf_audio_sink_class_init (GstGConfAudioSinkClass * klass)
|
||||||
GST_TYPE_GCONF_PROFILE, GCONF_PROFILE_SOUNDS, G_PARAM_READWRITE));
|
GST_TYPE_GCONF_PROFILE, GCONF_PROFILE_SOUNDS, G_PARAM_READWRITE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Hack to make negotiation work.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gconf_audio_sink_reset (GstGConfAudioSink * sink)
|
gst_gconf_audio_sink_reset (GstGConfAudioSink * sink)
|
||||||
{
|
{
|
||||||
GstPad *targetpad;
|
gst_switch_sink_set_child (GST_SWITCH_SINK (sink), NULL);
|
||||||
|
|
||||||
/* fakesink */
|
|
||||||
if (sink->kid) {
|
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
}
|
|
||||||
sink->kid = gst_element_factory_make ("fakesink", "testsink");
|
|
||||||
gst_bin_add (GST_BIN (sink), sink->kid);
|
|
||||||
|
|
||||||
targetpad = gst_element_get_pad (sink->kid, "sink");
|
|
||||||
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
|
|
||||||
gst_object_unref (targetpad);
|
|
||||||
|
|
||||||
g_free (sink->gconf_str);
|
g_free (sink->gconf_str);
|
||||||
sink->gconf_str = NULL;
|
sink->gconf_str = NULL;
|
||||||
|
|
||||||
if (sink->connection) {
|
gst_gconf_switch_profile (sink, GCONF_PROFILE_NONE);
|
||||||
gconf_client_notify_remove (sink->client, sink->connection);
|
|
||||||
sink->connection = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const gchar *
|
|
||||||
get_gconf_key_for_profile (int profile)
|
|
||||||
{
|
|
||||||
switch (profile) {
|
|
||||||
case GCONF_PROFILE_SOUNDS:
|
|
||||||
return GST_GCONF_DIR GST_GCONF_AUDIOSINK_KEY;
|
|
||||||
case GCONF_PROFILE_MUSIC:
|
|
||||||
return GST_GCONF_DIR GST_GCONF_MUSIC_AUDIOSINK_KEY;
|
|
||||||
case GCONF_PROFILE_CHAT:
|
|
||||||
return GST_GCONF_DIR GST_GCONF_CHAT_AUDIOSINK_KEY;
|
|
||||||
default:
|
|
||||||
g_return_val_if_reached (NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_gconf_audio_sink_init (GstGConfAudioSink * sink,
|
gst_gconf_audio_sink_init (GstGConfAudioSink * sink,
|
||||||
GstGConfAudioSinkClass * g_class)
|
GstGConfAudioSinkClass * g_class)
|
||||||
{
|
{
|
||||||
sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
|
|
||||||
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
|
|
||||||
|
|
||||||
gst_gconf_audio_sink_reset (sink);
|
gst_gconf_audio_sink_reset (sink);
|
||||||
|
|
||||||
sink->client = gconf_client_get_default ();
|
sink->client = gconf_client_get_default ();
|
||||||
gconf_client_add_dir (sink->client, GST_GCONF_DIR,
|
gconf_client_add_dir (sink->client, GST_GCONF_DIR "/default",
|
||||||
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
|
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
|
||||||
|
|
||||||
sink->profile = GCONF_PROFILE_SOUNDS;
|
gst_gconf_switch_profile (sink, GCONF_PROFILE_SOUNDS);
|
||||||
sink->connection = gconf_client_notify_add (sink->client,
|
|
||||||
get_gconf_key_for_profile (sink->profile), cb_toggle_element,
|
|
||||||
sink, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -171,11 +128,7 @@ gst_gconf_audio_sink_dispose (GObject * object)
|
||||||
GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (object);
|
GstGConfAudioSink *sink = GST_GCONF_AUDIO_SINK (object);
|
||||||
|
|
||||||
if (sink->client) {
|
if (sink->client) {
|
||||||
if (sink->connection) {
|
gst_gconf_switch_profile (sink, GCONF_PROFILE_NONE);
|
||||||
gconf_client_notify_remove (sink->client, sink->connection);
|
|
||||||
sink->connection = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref (G_OBJECT (sink->client));
|
g_object_unref (G_OBJECT (sink->client));
|
||||||
sink->client = NULL;
|
sink->client = NULL;
|
||||||
}
|
}
|
||||||
|
@ -187,12 +140,11 @@ gst_gconf_audio_sink_dispose (GObject * object)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
do_toggle_element (GstGConfAudioSink * sink)
|
do_change_child (GstGConfAudioSink * sink)
|
||||||
{
|
{
|
||||||
const gchar *key;
|
const gchar *key;
|
||||||
GstPad *targetpad;
|
|
||||||
gchar *new_gconf_str;
|
gchar *new_gconf_str;
|
||||||
GstState cur, next;
|
GstElement *new_kid;
|
||||||
|
|
||||||
key = gst_gconf_get_key_for_sink_profile (sink->profile);
|
key = gst_gconf_get_key_for_sink_profile (sink->profile);
|
||||||
new_gconf_str = gst_gconf_get_string (key);
|
new_gconf_str = gst_gconf_get_string (key);
|
||||||
|
@ -204,57 +156,65 @@ do_toggle_element (GstGConfAudioSink * sink)
|
||||||
(strlen (new_gconf_str) == 0 ||
|
(strlen (new_gconf_str) == 0 ||
|
||||||
strcmp (sink->gconf_str, new_gconf_str) == 0)) {
|
strcmp (sink->gconf_str, new_gconf_str) == 0)) {
|
||||||
g_free (new_gconf_str);
|
g_free (new_gconf_str);
|
||||||
GST_DEBUG_OBJECT (sink, "GConf key was updated, but it didn't change");
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sometime, it would be lovely to allow sink changes even when
|
|
||||||
* already running, but this involves sending an appropriate new-segment
|
|
||||||
* and possibly prerolling etc */
|
|
||||||
GST_OBJECT_LOCK (sink);
|
|
||||||
cur = GST_STATE (sink);
|
|
||||||
next = GST_STATE_PENDING (sink);
|
|
||||||
GST_OBJECT_UNLOCK (sink);
|
|
||||||
|
|
||||||
if (cur > GST_STATE_READY || next == GST_STATE_PAUSED) {
|
|
||||||
GST_DEBUG_OBJECT (sink,
|
GST_DEBUG_OBJECT (sink,
|
||||||
"Auto-sink is already running. Ignoring GConf change");
|
"GConf key was updated, but it didn't change. Ignoring");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sink, "GConf key changed: '%s' to '%s'",
|
GST_DEBUG_OBJECT (sink, "GConf key changed: '%s' to '%s'",
|
||||||
GST_STR_NULL (sink->gconf_str), GST_STR_NULL (new_gconf_str));
|
GST_STR_NULL (sink->gconf_str), GST_STR_NULL (new_gconf_str));
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "Creating new child for profile %d", sink->profile);
|
||||||
|
new_kid =
|
||||||
|
gst_gconf_render_bin_with_default (new_gconf_str, DEFAULT_AUDIOSINK);
|
||||||
|
|
||||||
|
if (new_kid == NULL) {
|
||||||
|
GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
|
||||||
|
("Failed to render audio sink from GConf"));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gst_switch_sink_set_child (GST_SWITCH_SINK (sink), new_kid)) {
|
||||||
|
GST_WARNING_OBJECT (sink, "Failed to update child element");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
g_free (sink->gconf_str);
|
g_free (sink->gconf_str);
|
||||||
sink->gconf_str = new_gconf_str;
|
sink->gconf_str = new_gconf_str;
|
||||||
|
|
||||||
/* kill old element */
|
|
||||||
if (sink->kid) {
|
|
||||||
GST_DEBUG_OBJECT (sink, "Removing old kid");
|
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
sink->kid = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sink, "Creating new kid");
|
|
||||||
if (!(sink->kid = gst_gconf_get_default_audio_sink (sink->profile))) {
|
|
||||||
GST_ELEMENT_ERROR (sink, LIBRARY, SETTINGS, (NULL),
|
|
||||||
("Failed to render audio sink from GConf"));
|
|
||||||
g_free (sink->gconf_str);
|
|
||||||
sink->gconf_str = NULL;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
gst_element_set_state (sink->kid, GST_STATE (sink));
|
|
||||||
gst_bin_add (GST_BIN (sink), sink->kid);
|
|
||||||
|
|
||||||
/* re-attach ghostpad */
|
|
||||||
GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
|
|
||||||
targetpad = gst_element_get_pad (sink->kid, "sink");
|
|
||||||
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
|
|
||||||
gst_object_unref (targetpad);
|
|
||||||
GST_DEBUG_OBJECT (sink, "done changing gconf audio sink");
|
GST_DEBUG_OBJECT (sink, "done changing gconf audio sink");
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
g_free (new_gconf_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_gconf_switch_profile (GstGConfAudioSink * sink, GstGConfProfile profile)
|
||||||
|
{
|
||||||
|
if (sink->client == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sink->connection) {
|
||||||
|
const gchar *key = gst_gconf_get_key_for_sink_profile (sink->profile);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "Unsubscribing old key %s for profile %d",
|
||||||
|
key, sink->profile);
|
||||||
|
gconf_client_notify_remove (sink->client, sink->connection);
|
||||||
|
sink->connection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink->profile = profile;
|
||||||
|
if (profile != GCONF_PROFILE_NONE) {
|
||||||
|
const gchar *key = gst_gconf_get_key_for_sink_profile (sink->profile);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "Subscribing to key %s for profile %d",
|
||||||
|
key, profile);
|
||||||
|
sink->connection = gconf_client_notify_add (sink->client, key,
|
||||||
|
cb_change_child, sink, NULL, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -267,13 +227,7 @@ gst_gconf_audio_sink_set_property (GObject * object, guint prop_id,
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PROFILE:
|
case PROP_PROFILE:
|
||||||
sink->profile = g_value_get_enum (value);
|
gst_gconf_switch_profile (sink, g_value_get_enum (value));
|
||||||
if (sink->connection) {
|
|
||||||
gconf_client_notify_remove (sink->client, sink->connection);
|
|
||||||
}
|
|
||||||
sink->connection = gconf_client_notify_add (sink->client,
|
|
||||||
get_gconf_key_for_profile (sink->profile), cb_toggle_element,
|
|
||||||
sink, NULL, NULL);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -299,10 +253,10 @@ gst_gconf_audio_sink_get_property (GObject * object, guint prop_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cb_toggle_element (GConfClient * client,
|
cb_change_child (GConfClient * client,
|
||||||
guint connection_id, GConfEntry * entry, gpointer data)
|
guint connection_id, GConfEntry * entry, gpointer data)
|
||||||
{
|
{
|
||||||
do_toggle_element (GST_GCONF_AUDIO_SINK (data));
|
do_change_child (GST_GCONF_AUDIO_SINK (data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
|
@ -314,8 +268,10 @@ gst_gconf_audio_sink_change_state (GstElement * element,
|
||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
if (!do_toggle_element (sink))
|
if (!do_change_child (sink)) {
|
||||||
|
gst_gconf_audio_sink_reset (sink);
|
||||||
return GST_STATE_CHANGE_FAILURE;
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gconf/gconf-client.h>
|
#include <gconf/gconf-client.h>
|
||||||
|
#include "gstswitchsink.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -39,21 +40,19 @@ G_BEGIN_DECLS
|
||||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_AUDIO_SINK))
|
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_GCONF_AUDIO_SINK))
|
||||||
|
|
||||||
typedef struct _GstGConfAudioSink {
|
typedef struct _GstGConfAudioSink {
|
||||||
GstBin parent;
|
GstSwitchSink parent;
|
||||||
|
|
||||||
/* explicit pointers to stuff used */
|
/* explicit pointers to stuff used */
|
||||||
GConfClient *client;
|
GConfClient *client;
|
||||||
int profile;
|
GstGConfProfile profile;
|
||||||
guint connection;
|
guint connection;
|
||||||
GstElement *kid;
|
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
/* Current gconf string */
|
/* Current gconf string */
|
||||||
gchar *gconf_str;
|
gchar *gconf_str;
|
||||||
} GstGConfAudioSink;
|
} GstGConfAudioSink;
|
||||||
|
|
||||||
typedef struct _GstGConfAudioSinkClass {
|
typedef struct _GstGConfAudioSinkClass {
|
||||||
GstBinClass parent_class;
|
GstSwitchSinkClass parent_class;
|
||||||
} GstGConfAudioSinkClass;
|
} GstGConfAudioSinkClass;
|
||||||
|
|
||||||
GType gst_gconf_audio_sink_get_type (void);
|
GType gst_gconf_audio_sink_get_type (void);
|
||||||
|
|
265
ext/gconf/gstswitchsink.c
Normal file
265
ext/gconf/gstswitchsink.c
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
/* GStreamer
|
||||||
|
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
* (c) 2006 Jürg Billeter <j@bitron.ch>
|
||||||
|
* (c) 2007 Jan Schmidt <thaytan@noraisin.net>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gstswitchsink.h"
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (switch_debug);
|
||||||
|
#define GST_CAT_DEFAULT switch_debug
|
||||||
|
|
||||||
|
static void gst_switch_sink_dispose (GObject * object);
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_switch_sink_change_state (GstElement * element, GstStateChange transition);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_BOILERPLATE (GstSwitchSink, gst_switch_sink, GstBin, GST_TYPE_BIN);
|
||||||
|
|
||||||
|
static void gst_switch_sink_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec);
|
||||||
|
static void gst_switch_sink_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec);
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_base_init (gpointer klass)
|
||||||
|
{
|
||||||
|
GST_DEBUG_CATEGORY_INIT (switch_debug, "switchsink", 0, "switchsink element");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_class_init (GstSwitchSinkClass * klass)
|
||||||
|
{
|
||||||
|
GObjectClass *oklass = G_OBJECT_CLASS (klass);
|
||||||
|
GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
|
||||||
|
GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_STATIC_CAPS_ANY);
|
||||||
|
GstPadTemplate *child_pad_templ;
|
||||||
|
|
||||||
|
oklass->set_property = gst_switch_sink_set_property;
|
||||||
|
oklass->get_property = gst_switch_sink_get_property;
|
||||||
|
oklass->dispose = gst_switch_sink_dispose;
|
||||||
|
eklass->change_state = gst_switch_sink_change_state;
|
||||||
|
|
||||||
|
/* Provide a default pad template if the child didn't */
|
||||||
|
child_pad_templ = gst_element_class_get_pad_template (eklass, "sink");
|
||||||
|
if (child_pad_templ == NULL) {
|
||||||
|
gst_element_class_add_pad_template (eklass,
|
||||||
|
gst_static_pad_template_get (&sink_template));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_reset (GstSwitchSink * sink)
|
||||||
|
{
|
||||||
|
/* fakesink */
|
||||||
|
if (sink->kid == NULL) {
|
||||||
|
gst_switch_sink_set_child (sink, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_init (GstSwitchSink * sink, GstSwitchSinkClass * g_class)
|
||||||
|
{
|
||||||
|
sink->pad = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (sink), sink->pad);
|
||||||
|
|
||||||
|
gst_switch_sink_reset (sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_dispose (GObject * object)
|
||||||
|
{
|
||||||
|
GstSwitchSink *sink = GST_SWITCH_SINK (object);
|
||||||
|
GstElement **p_kid = &sink->kid;
|
||||||
|
|
||||||
|
gst_object_replace ((GstObject **) p_kid, NULL);
|
||||||
|
|
||||||
|
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_switch_commit_new_kid (GstSwitchSink * sink)
|
||||||
|
{
|
||||||
|
GstPad *targetpad;
|
||||||
|
GstState cur_state;
|
||||||
|
GstElement *new_kid, *old_kid;
|
||||||
|
gboolean is_fakesink = FALSE;
|
||||||
|
|
||||||
|
/* need locking around member accesses */
|
||||||
|
GST_OBJECT_LOCK (sink);
|
||||||
|
cur_state = GST_STATE (sink);
|
||||||
|
new_kid = sink->new_kid;
|
||||||
|
sink->new_kid = NULL;
|
||||||
|
GST_OBJECT_UNLOCK (sink);
|
||||||
|
|
||||||
|
/* Fakesink by default if NULL is passed as the new child */
|
||||||
|
if (new_kid == NULL) {
|
||||||
|
GST_DEBUG_OBJECT (sink, "Replacing kid with fakesink");
|
||||||
|
new_kid = gst_element_factory_make ("fakesink", "testsink");
|
||||||
|
g_object_set (new_kid, "sync", TRUE, NULL);
|
||||||
|
is_fakesink = TRUE;
|
||||||
|
} else {
|
||||||
|
GST_DEBUG_OBJECT (sink, "Setting new kid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gst_element_set_state (new_kid, cur_state) == GST_STATE_CHANGE_FAILURE) {
|
||||||
|
GST_ELEMENT_ERROR (sink, CORE, STATE_CHANGE, (NULL),
|
||||||
|
("Failed to set state on new child."));
|
||||||
|
gst_object_unref (new_kid);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
gst_bin_add (GST_BIN (sink), new_kid);
|
||||||
|
|
||||||
|
/* Now, replace the existing child */
|
||||||
|
GST_OBJECT_LOCK (sink);
|
||||||
|
old_kid = sink->kid;
|
||||||
|
sink->kid = new_kid;
|
||||||
|
GST_OBJECT_UNLOCK (sink);
|
||||||
|
|
||||||
|
/* kill old element */
|
||||||
|
if (old_kid) {
|
||||||
|
GST_DEBUG_OBJECT (sink, "Removing old kid %" GST_PTR_FORMAT, old_kid);
|
||||||
|
gst_element_set_state (old_kid, GST_STATE_NULL);
|
||||||
|
gst_bin_remove (GST_BIN (sink), old_kid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-attach ghostpad */
|
||||||
|
GST_DEBUG_OBJECT (sink, "Creating new ghostpad");
|
||||||
|
targetpad = gst_element_get_pad (sink->kid, "sink");
|
||||||
|
gst_ghost_pad_set_target (GST_GHOST_PAD (sink->pad), targetpad);
|
||||||
|
gst_object_unref (targetpad);
|
||||||
|
GST_DEBUG_OBJECT (sink, "done changing child of switchsink");
|
||||||
|
|
||||||
|
/* FIXME: Push new-segment info and pre-roll buffer(s) into the kid */
|
||||||
|
|
||||||
|
/* Unblock the target pad if necessary */
|
||||||
|
if (sink->awaiting_block) {
|
||||||
|
gst_pad_set_blocked (sink->pad, FALSE);
|
||||||
|
sink->awaiting_block = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_switch_sink_set_child (GstSwitchSink * sink, GstElement * new_kid)
|
||||||
|
{
|
||||||
|
GstState cur, next;
|
||||||
|
GstElement **p_kid;
|
||||||
|
|
||||||
|
/* Nothing to do if clearing the child and we don't have one anyway */
|
||||||
|
if (new_kid == NULL && sink->have_kid == FALSE)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (sink);
|
||||||
|
cur = GST_STATE (sink);
|
||||||
|
next = GST_STATE_NEXT (sink);
|
||||||
|
p_kid = &sink->new_kid;
|
||||||
|
gst_object_replace ((GstObject **) p_kid, (GstObject *) new_kid);
|
||||||
|
GST_OBJECT_UNLOCK (sink);
|
||||||
|
|
||||||
|
if (cur == GST_STATE_PAUSED && next == GST_STATE_READY) {
|
||||||
|
return gst_switch_commit_new_kid (sink);
|
||||||
|
}
|
||||||
|
/* Sometime, it would be lovely to allow sink changes even when
|
||||||
|
* already running, but this involves sending an appropriate new-segment
|
||||||
|
* and possibly prerolling etc */
|
||||||
|
/* FIXME: Block the pad and replace the kid when it completes */
|
||||||
|
if (cur > GST_STATE_READY || next == GST_STATE_PAUSED) {
|
||||||
|
GST_DEBUG_OBJECT (sink,
|
||||||
|
"Switch-sink is already running. Ignoring change of child.");
|
||||||
|
gst_object_unref (new_kid);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gst_switch_commit_new_kid (sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_set_property (GObject * object, guint prop_id,
|
||||||
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstSwitchSink *sink;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_SWITCH_SINK (object));
|
||||||
|
|
||||||
|
sink = GST_SWITCH_SINK (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static gboolean
|
||||||
|
gst_switch_sink_handle_event (GstPad * pad, GstEvent * event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_switch_sink_get_property (GObject * object, guint prop_id,
|
||||||
|
GValue * value, GParamSpec * pspec)
|
||||||
|
{
|
||||||
|
GstSwitchSink *sink;
|
||||||
|
|
||||||
|
g_return_if_fail (GST_IS_SWITCH_SINK (object));
|
||||||
|
|
||||||
|
sink = GST_SWITCH_SINK (object);
|
||||||
|
|
||||||
|
switch (prop_id) {
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_switch_sink_change_state (GstElement * element, GstStateChange transition)
|
||||||
|
{
|
||||||
|
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||||
|
GstSwitchSink *sink = GST_SWITCH_SINK (element);
|
||||||
|
|
||||||
|
ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
|
||||||
|
(element, transition), GST_STATE_CHANGE_SUCCESS);
|
||||||
|
|
||||||
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
gst_switch_sink_reset (sink);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
68
ext/gconf/gstswitchsink.h
Normal file
68
ext/gconf/gstswitchsink.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* GStreamer
|
||||||
|
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
* (c) 2007 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GST_SWITCH_SINK_H__
|
||||||
|
#define __GST_SWITCH_SINK_H__
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GST_TYPE_SWITCH_SINK \
|
||||||
|
(gst_switch_sink_get_type ())
|
||||||
|
#define GST_SWITCH_SINK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_SWITCH_SINK, \
|
||||||
|
GstSwitchSink))
|
||||||
|
#define GST_SWITCH_SINK_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_SWITCH_SINK, \
|
||||||
|
GstSwitchSinkClass))
|
||||||
|
#define GST_IS_SWITCH_SINK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_SWITCH_SINK))
|
||||||
|
#define GST_IS_SWITCH_SINK_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_SWITCH_SINK))
|
||||||
|
|
||||||
|
typedef struct _GstSwitchSink {
|
||||||
|
GstBin parent;
|
||||||
|
|
||||||
|
GstElement *kid;
|
||||||
|
GstElement *new_kid;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
/* Track incoming segment info for switchover */
|
||||||
|
GstSegment segment;
|
||||||
|
|
||||||
|
/* If a custom child has been set... */
|
||||||
|
gboolean have_kid;
|
||||||
|
|
||||||
|
/* If waiting for a pad block to complete on the ghost pad */
|
||||||
|
gboolean awaiting_block;
|
||||||
|
} GstSwitchSink;
|
||||||
|
|
||||||
|
typedef struct _GstSwitchSinkClass {
|
||||||
|
GstBinClass parent_class;
|
||||||
|
} GstSwitchSinkClass;
|
||||||
|
|
||||||
|
GType gst_switch_sink_get_type (void);
|
||||||
|
|
||||||
|
gboolean gst_switch_sink_set_child (GstSwitchSink *ssink, GstElement *new_kid);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_SWITCH_SINK_H__ */
|
|
@ -1,5 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
* (c) 2006 Jan Schmidt <thaytan@noraisin.net>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -49,6 +50,8 @@
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_auto_audio_sink_change_state (GstElement * element,
|
gst_auto_audio_sink_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
static void gst_auto_audio_sink_dispose (GstAutoAudioSink * sink);
|
||||||
|
static void gst_auto_audio_sink_clear_kid (GstAutoAudioSink * sink);
|
||||||
|
|
||||||
GST_BOILERPLATE (GstAutoAudioSink, gst_auto_audio_sink, GstBin, GST_TYPE_BIN);
|
GST_BOILERPLATE (GstAutoAudioSink, gst_auto_audio_sink, GstBin, GST_TYPE_BIN);
|
||||||
|
|
||||||
|
@ -56,7 +59,8 @@ static const GstElementDetails gst_auto_audio_sink_details =
|
||||||
GST_ELEMENT_DETAILS ("Auto audio sink",
|
GST_ELEMENT_DETAILS ("Auto audio sink",
|
||||||
"Sink/Audio",
|
"Sink/Audio",
|
||||||
"Wrapper audio sink for automatically detected audio sink",
|
"Wrapper audio sink for automatically detected audio sink",
|
||||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
|
"Ronald Bultje <rbultje@ronald.bitfreak.net>\n"
|
||||||
|
"Jan Schmidt <thaytan@noraisin.net");
|
||||||
|
|
||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -77,13 +81,35 @@ gst_auto_audio_sink_base_init (gpointer klass)
|
||||||
static void
|
static void
|
||||||
gst_auto_audio_sink_class_init (GstAutoAudioSinkClass * klass)
|
gst_auto_audio_sink_class_init (GstAutoAudioSinkClass * klass)
|
||||||
{
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *eklass;
|
GstElementClass *eklass;
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
eklass = GST_ELEMENT_CLASS (klass);
|
eklass = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->dispose =
|
||||||
|
(GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_audio_sink_dispose);
|
||||||
eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_audio_sink_change_state);
|
eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_audio_sink_change_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_auto_audio_sink_dispose (GstAutoAudioSink * sink)
|
||||||
|
{
|
||||||
|
gst_auto_audio_sink_clear_kid (sink);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_auto_audio_sink_clear_kid (GstAutoAudioSink * sink)
|
||||||
|
{
|
||||||
|
if (sink->kid) {
|
||||||
|
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
||||||
|
gst_bin_remove (GST_BIN (sink), sink->kid);
|
||||||
|
sink->kid = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hack to make initial linking work; ideally, this'd work even when
|
* Hack to make initial linking work; ideally, this'd work even when
|
||||||
* no target has been assigned to the ghostpad yet.
|
* no target has been assigned to the ghostpad yet.
|
||||||
|
@ -94,11 +120,9 @@ gst_auto_audio_sink_reset (GstAutoAudioSink * sink)
|
||||||
{
|
{
|
||||||
GstPad *targetpad;
|
GstPad *targetpad;
|
||||||
|
|
||||||
|
gst_auto_audio_sink_clear_kid (sink);
|
||||||
|
|
||||||
/* fakesink placeholder */
|
/* fakesink placeholder */
|
||||||
if (sink->kid) {
|
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
}
|
|
||||||
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
|
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
|
||||||
gst_bin_add (GST_BIN (sink), sink->kid);
|
gst_bin_add (GST_BIN (sink), sink->kid);
|
||||||
|
|
||||||
|
@ -258,11 +282,7 @@ gst_auto_audio_sink_detect (GstAutoAudioSink * sink)
|
||||||
GstElement *esink;
|
GstElement *esink;
|
||||||
GstPad *targetpad;
|
GstPad *targetpad;
|
||||||
|
|
||||||
if (sink->kid) {
|
gst_auto_audio_sink_clear_kid (sink);
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
sink->kid = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find element */
|
/* find element */
|
||||||
GST_DEBUG_OBJECT (sink, "Creating new kid");
|
GST_DEBUG_OBJECT (sink, "Creating new kid");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
* (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||||
|
* (c) 2006 Jan Schmidt <thaytan@noraisin.net>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -49,6 +50,8 @@
|
||||||
static GstStateChangeReturn
|
static GstStateChangeReturn
|
||||||
gst_auto_video_sink_change_state (GstElement * element,
|
gst_auto_video_sink_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
|
static void gst_auto_video_sink_dispose (GstAutoVideoSink * sink);
|
||||||
|
static void gst_auto_video_sink_clear_kid (GstAutoVideoSink * sink);
|
||||||
|
|
||||||
GST_BOILERPLATE (GstAutoVideoSink, gst_auto_video_sink, GstBin, GST_TYPE_BIN);
|
GST_BOILERPLATE (GstAutoVideoSink, gst_auto_video_sink, GstBin, GST_TYPE_BIN);
|
||||||
|
|
||||||
|
@ -56,7 +59,8 @@ static const GstElementDetails gst_auto_video_sink_details =
|
||||||
GST_ELEMENT_DETAILS ("Auto video sink",
|
GST_ELEMENT_DETAILS ("Auto video sink",
|
||||||
"Sink/Video",
|
"Sink/Video",
|
||||||
"Wrapper video sink for automatically detected video sink",
|
"Wrapper video sink for automatically detected video sink",
|
||||||
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
|
"Ronald Bultje <rbultje@ronald.bitfreak.net>\n"
|
||||||
|
"Jan Schmidt <thaytan@noraisin.net");
|
||||||
|
|
||||||
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
|
@ -76,11 +80,33 @@ gst_auto_video_sink_base_init (gpointer klass)
|
||||||
static void
|
static void
|
||||||
gst_auto_video_sink_class_init (GstAutoVideoSinkClass * klass)
|
gst_auto_video_sink_class_init (GstAutoVideoSinkClass * klass)
|
||||||
{
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
|
GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class = G_OBJECT_CLASS (klass);
|
||||||
|
gobject_class->dispose =
|
||||||
|
(GObjectFinalizeFunc) GST_DEBUG_FUNCPTR (gst_auto_video_sink_dispose);
|
||||||
eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_video_sink_change_state);
|
eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_video_sink_change_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_auto_video_sink_dispose (GstAutoVideoSink * sink)
|
||||||
|
{
|
||||||
|
gst_auto_video_sink_clear_kid (sink);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->dispose ((GObject *) sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_auto_video_sink_clear_kid (GstAutoVideoSink * sink)
|
||||||
|
{
|
||||||
|
if (sink->kid) {
|
||||||
|
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
||||||
|
gst_bin_remove (GST_BIN (sink), sink->kid);
|
||||||
|
sink->kid = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hack to make initial linking work; ideally, this'd work even when
|
* Hack to make initial linking work; ideally, this'd work even when
|
||||||
* no target has been assigned to the ghostpad yet.
|
* no target has been assigned to the ghostpad yet.
|
||||||
|
@ -91,11 +117,10 @@ gst_auto_video_sink_reset (GstAutoVideoSink * sink)
|
||||||
{
|
{
|
||||||
GstPad *targetpad;
|
GstPad *targetpad;
|
||||||
|
|
||||||
|
/* Remove any existing element */
|
||||||
|
gst_auto_video_sink_clear_kid (sink);
|
||||||
|
|
||||||
/* fakesink placeholder */
|
/* fakesink placeholder */
|
||||||
if (sink->kid) {
|
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
}
|
|
||||||
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
|
sink->kid = gst_element_factory_make ("fakesink", "tempsink");
|
||||||
gst_bin_add (GST_BIN (sink), sink->kid);
|
gst_bin_add (GST_BIN (sink), sink->kid);
|
||||||
|
|
||||||
|
@ -204,11 +229,7 @@ gst_auto_video_sink_detect (GstAutoVideoSink * sink)
|
||||||
GstElement *esink;
|
GstElement *esink;
|
||||||
GstPad *targetpad;
|
GstPad *targetpad;
|
||||||
|
|
||||||
if (sink->kid) {
|
gst_auto_video_sink_clear_kid (sink);
|
||||||
gst_element_set_state (sink->kid, GST_STATE_NULL);
|
|
||||||
gst_bin_remove (GST_BIN (sink), sink->kid);
|
|
||||||
sink->kid = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find element */
|
/* find element */
|
||||||
GST_DEBUG_OBJECT (sink, "Creating new kid");
|
GST_DEBUG_OBJECT (sink, "Creating new kid");
|
||||||
|
|
Loading…
Reference in a new issue