diff options
Diffstat (limited to 'examples/scaletempo/demo-player.c')
-rw-r--r-- | examples/scaletempo/demo-player.c | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/examples/scaletempo/demo-player.c b/examples/scaletempo/demo-player.c new file mode 100644 index 00000000..3ed4b718 --- /dev/null +++ b/examples/scaletempo/demo-player.c @@ -0,0 +1,756 @@ +/* demo-player.c + * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "demo-player.h" +#include "gst/gst.h" + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "demo-player" + +enum +{ + SIGNAL_ERROR, + SIGNAL_RATE_CHANGE, + SIGNAL_PLAYING_STARTED, + SIGNAL_PLAYING_PAUSED, + SIGNAL_PLAYING_ENDED, + LAST_SIGNAL +}; +static guint demo_player_signals[LAST_SIGNAL] = { 0 }; + +enum +{ + PROP_0, + PROP_RATE, + PROP_STRIDE, + PROP_OVERLAP, + PROP_SEARCH, + PROP_DISABLED +}; + +typedef struct _DemoPlayerPrivate +{ + gdouble rate; + GstElement *scaletempo; + GstElement *pipeline; + gboolean is_disabled; + GstElement *scaletempo_line; + GstElement *scalerate_line; + gboolean ignore_state_change; +} DemoPlayerPrivate; + +#define DEMO_PLAYER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEMO_TYPE_PLAYER, DemoPlayerPrivate)) + + +static gboolean +no_pipeline (DemoPlayer * player) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + if (!priv->pipeline) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "No media loaded"); + return TRUE; + } + return FALSE; +} + +static gboolean +demo_player_event_listener (GstElement * host, GstEvent * event, gpointer data) +{ + DemoPlayer *player = DEMO_PLAYER (data); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) { + gdouble rate, applied_rate; + gdouble new_rate; + + gst_event_parse_new_segment_full (event, NULL, &rate, &applied_rate, NULL, + NULL, NULL, NULL); + new_rate = rate * applied_rate; + if (priv->rate != new_rate) { + priv->rate = new_rate; + g_signal_emit (player, demo_player_signals[SIGNAL_RATE_CHANGE], 0, + new_rate); + } + } + + return TRUE; +} + +static void +demo_player_state_changed_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + DemoPlayer *player = DEMO_PLAYER (data); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + GstState old, new, pending; + + if (GST_ELEMENT (GST_MESSAGE_SRC (message)) != priv->pipeline) + return; + + gst_message_parse_state_changed (message, &old, &new, &pending); + + if (pending == GST_STATE_VOID_PENDING) { + if (priv->ignore_state_change) { + priv->ignore_state_change = FALSE; + } else if (new == GST_STATE_PAUSED) { + g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_PAUSED], 0); + } else if (new == GST_STATE_PLAYING) { + g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_STARTED], 0); + } + } +} + +static void +demo_player_eos_cb (GstBus * bus, GstMessage * message, gpointer data) +{ + DemoPlayer *player = DEMO_PLAYER (data); + g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_ENDED], 0); +} + +#define MAKE_ELEMENT(line, var, type, name) \ + if ( !(var = gst_element_factory_make (type, name) ) ) { \ + g_print ("element could not be created: %s/%s\n", type, name); \ + return; \ + } \ + if (line) gst_bin_add (GST_BIN (line), var); + +#define LINK_ELEMENTS(src, sink) \ + if (!gst_element_link (src, sink)) { \ + g_warning ("Failed to link elements: %s -> %s", \ + GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink) ); \ + return; \ + } + +static void +demo_player_build_pipeline (DemoPlayer * player) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + GstElement *filter, *playbin, *vsink, *audioline, *format, *resample, *asink; + GstPlugin *gconf; + GstBus *bus; + gboolean has_gconf; + const gchar *audiosink_name; + GstPad *ghostpad; + + priv->pipeline = NULL; + if (!priv->scaletempo) { + return; + } + + filter = priv->scaletempo; + + MAKE_ELEMENT (NULL, playbin, "playbin", "playbin"); + + gconf = gst_default_registry_find_plugin ("gconfelements"); + has_gconf = (gconf != NULL); + gst_object_unref (gconf); + + if (has_gconf) { + MAKE_ELEMENT (NULL, vsink, "gconfvideosink", "vsink"); + g_object_set (G_OBJECT (playbin), "video_sink", vsink, NULL); + } + audiosink_name = has_gconf ? "gconfaudiosink" : "autoaudiosink"; + + audioline = gst_bin_new ("audioline"); + gst_bin_add (GST_BIN (audioline), filter); + MAKE_ELEMENT (audioline, format, "audioconvert", "format"); + MAKE_ELEMENT (audioline, resample, "audioresample", "resample"); + MAKE_ELEMENT (audioline, asink, audiosink_name, "audio_sink"); + LINK_ELEMENTS (filter, format); + LINK_ELEMENTS (format, resample); + LINK_ELEMENTS (resample, asink); + + gst_pad_add_event_probe (gst_element_get_static_pad (asink, "sink"), + G_CALLBACK (demo_player_event_listener), player); + + ghostpad = gst_element_get_static_pad (filter, "sink"); + gst_element_add_pad (audioline, gst_ghost_pad_new ("sink", ghostpad)); + gst_object_unref (ghostpad); + g_object_set (G_OBJECT (playbin), "audio-sink", audioline, NULL); + + bus = gst_pipeline_get_bus (GST_PIPELINE (playbin)); + gst_bus_add_signal_watch (bus); + g_signal_connect (bus, "message::state-changed", + G_CALLBACK (demo_player_state_changed_cb), player); + g_signal_connect (bus, "message::eos", G_CALLBACK (demo_player_eos_cb), + player); + gst_object_unref (bus); + + priv->scaletempo = filter; + priv->pipeline = playbin; + + priv->scaletempo_line = audioline; + MAKE_ELEMENT (NULL, priv->scalerate_line, "gconfaudiosink", + "scaling_audio_sink"); + gst_pad_add_event_probe (gst_element_get_static_pad (priv->scalerate_line, + "sink"), G_CALLBACK (demo_player_event_listener), player); + g_object_ref (priv->scaletempo_line); + g_object_ref (priv->scalerate_line); +} + + +/* method implementations */ +static void +_set_rate (DemoPlayer * player, gdouble new_rate, gint second) +{ + DemoPlayerPrivate *priv; + gint64 pos; + GstSeekType seek_type; + + + if (new_rate == 0) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Cannot set playback to zero. Pausing instead."); + demo_player_pause (player); + } + + priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (second < 0) { + GstFormat fmt = GST_FORMAT_TIME; + seek_type = GST_SEEK_TYPE_SET; + if (!gst_element_query_position (priv->pipeline, &fmt, &pos)) { + // This should be the default but too many upstream elements seek anyway + pos = GST_CLOCK_TIME_NONE; + seek_type = GST_SEEK_TYPE_NONE; + } + } else { + seek_type = GST_SEEK_TYPE_SET; + pos = second * GST_SECOND; + } + + if (!gst_element_seek (priv->pipeline, new_rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, + seek_type, pos, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Unable to change playback rate"); + } else { + priv->ignore_state_change = TRUE; + } +} + +static void +demo_player_scale_rate_func (DemoPlayer * player, gdouble scale) +{ + DemoPlayerPrivate *priv; + if (no_pipeline (player)) + return; + + priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (scale != 1.0) { + g_message ("Scaling Rate by: %3.2f", scale); + _set_rate (player, priv->rate * scale, -1); + } +} + +static void +demo_player_set_rate_func (DemoPlayer * player, gdouble new_rate) +{ + DemoPlayerPrivate *priv; + + if (no_pipeline (player)) + return; + + priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (priv->rate != new_rate) { + g_message ("Setting Rate to: %3.2f", new_rate); + _set_rate (player, new_rate, -1); + } +} + +static gboolean +_set_state_and_wait (DemoPlayer * player, + GstState new_state, GstClockTime timeout, const gchar * error_msg) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + GstStateChangeReturn ret = gst_element_set_state (priv->pipeline, new_state); + if (ret == GST_STATE_CHANGE_ASYNC) { + ret = gst_element_get_state (priv->pipeline, NULL, NULL, timeout); + } + if (ret != GST_STATE_CHANGE_SUCCESS) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, error_msg); + return FALSE; + } + return TRUE; +} + +static void +demo_player_load_uri_func (DemoPlayer * player, gchar * uri) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + GstState end_state; + gdouble rate; + + if (!priv->pipeline) { + demo_player_build_pipeline (player); + if (!priv->pipeline) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Could not build player"); + return; + } + } + if (!g_str_has_prefix (uri, "file:///")) { + GError *err = NULL; + if (g_path_is_absolute (uri)) { + uri = g_filename_to_uri (uri, NULL, &err); + } else { + gchar *curdir = g_get_current_dir (); + gchar *absolute_path = g_strconcat (curdir, G_DIR_SEPARATOR_S, uri, NULL); + uri = g_filename_to_uri (absolute_path, NULL, &err); + g_free (absolute_path); + g_free (curdir); + } + if (err) { + gchar *msg = g_strconcat ("Could not load uri: ", err->message, NULL); + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, msg); + return; + } + } + + g_message ("Loading URI: %s", uri); + + end_state = + (GST_STATE (priv->pipeline) == + GST_STATE_PLAYING) ? GST_STATE_PLAYING : GST_STATE_PAUSED; + if (!_set_state_and_wait (player, GST_STATE_NULL, 10 * GST_SECOND, + "Unable to load uri")) + return; + + g_object_set (G_OBJECT (priv->pipeline), "uri", uri, NULL); + + rate = priv->rate; + if (rate && rate != 1.0) { + _set_state_and_wait (player, GST_STATE_PAUSED, 10 * GST_SECOND, + "Unable to keep playback rate"); + _set_rate (player, rate, -1); + } + + gst_element_set_state (priv->pipeline, end_state); +} + +static void +demo_player_play_func (DemoPlayer * player) +{ + DemoPlayerPrivate *priv; + GstStateChangeReturn ret; + + if (no_pipeline (player)) + return; + + priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (GST_STATE (priv->pipeline) == GST_STATE_PLAYING) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Already playing"); + return; + } + + g_debug ("Starting to Play"); + ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Unable to start playback"); + return; + } +} + +static void +demo_player_pause_func (DemoPlayer * player) +{ + DemoPlayerPrivate *priv; + GstStateChangeReturn ret; + + if (no_pipeline (player)) + return; + + priv = DEMO_PLAYER_GET_PRIVATE (player); + + if (GST_STATE (priv->pipeline) == GST_STATE_PAUSED) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Already paused"); + return; + } + + g_debug ("Starting to Pause"); + ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED); + if (ret == GST_STATE_CHANGE_FAILURE) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Unable to pause playback"); + return; + } +} + +static void +_seek_to (DemoPlayer * player, gint new_second) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + if (!gst_element_seek (priv->pipeline, priv->rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, new_second * GST_SECOND, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek failed"); + return; + } + + priv->ignore_state_change = TRUE; +} + +static void +demo_player_seek_by_func (DemoPlayer * player, gint seconds) +{ + gint pos; + + if (no_pipeline (player)) + return; + + g_debug ("Seeking by: %i", seconds); + + pos = demo_player_get_position (player); + if (pos < 0) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Seek-by failed: could not determine position"); + return; + } + + _seek_to (player, MAX (0, pos + seconds)); +} + +static void +demo_player_seek_to_func (DemoPlayer * player, gint second) +{ + gint new_second; + + if (no_pipeline (player)) + return; + + g_debug ("Seeking to: %i", second); + + if (second < 0) { + gint dur = demo_player_get_duration (player); + if (dur < 0) { + g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, + "Seek-to failed: could not determine duration"); + return; + } + new_second = MAX (0, dur + second); + } else { + new_second = second; + } + + _seek_to (player, new_second); +} + +static gint +demo_player_get_position_func (DemoPlayer * player) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + gint64 pos; + GstFormat fmt = GST_FORMAT_TIME; + + if (!priv->pipeline) + return -1; + + if (!gst_element_query_position (priv->pipeline, &fmt, &pos) || pos < 0) { + return -1; + } + + return (gint) (pos / GST_SECOND); +} + +static gint +demo_player_get_duration_func (DemoPlayer * player) +{ + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + gint64 dur; + GstFormat fmt = GST_FORMAT_TIME; + + if (!priv->pipeline) + return -1; + + if (!gst_element_query_duration (priv->pipeline, &fmt, &dur) || dur < 0) { + return -1; + } + + return (gint) (dur / GST_SECOND); +} + + +/* Method wrappers */ +void +demo_player_scale_rate (DemoPlayer * player, gdouble scale) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->scale_rate (player, scale); +} + +void +demo_player_set_rate (DemoPlayer * player, gdouble new_rate) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->set_rate (player, new_rate); +} + +void +demo_player_load_uri (DemoPlayer * player, gchar * uri) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->load_uri (player, uri); +} + +void +demo_player_play (DemoPlayer * player) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->play (player); +} + +void +demo_player_pause (DemoPlayer * player) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->pause (player); +} + +void +demo_player_seek_by (DemoPlayer * player, gint seconds) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->seek_by (player, seconds); +} + +void +demo_player_seek_to (DemoPlayer * player, gint second) +{ + g_return_if_fail (DEMO_IS_PLAYER (player)); + + DEMO_PLAYER_GET_CLASS (player)->seek_to (player, second); +} + +gint +demo_player_get_position (DemoPlayer * player) +{ + g_return_val_if_fail (DEMO_IS_PLAYER (player), -1); + + return DEMO_PLAYER_GET_CLASS (player)->get_position (player); +} + +gint +demo_player_get_duration (DemoPlayer * player) +{ + g_return_val_if_fail (DEMO_IS_PLAYER (player), -1); + + return DEMO_PLAYER_GET_CLASS (player)->get_duration (player); +} + +/* GObject overrides */ +static void +demo_player_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec) +{ + DemoPlayer *player = DEMO_PLAYER (object); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + switch (property_id) { + case PROP_RATE: + g_value_set_double (value, priv->rate); + break; + case PROP_STRIDE: + g_object_get_property (G_OBJECT (priv->scaletempo), "stride", value); + break; + case PROP_OVERLAP: + g_object_get_property (G_OBJECT (priv->scaletempo), "overlap", value); + break; + case PROP_SEARCH: + g_object_get_property (G_OBJECT (priv->scaletempo), "search", value); + break; + case PROP_DISABLED: + g_value_set_boolean (value, priv->is_disabled); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +demo_player_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec) +{ + DemoPlayer *player = DEMO_PLAYER (object); + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + switch (property_id) { + case PROP_STRIDE: + g_object_set_property (G_OBJECT (priv->scaletempo), "stride", value); + break; + case PROP_OVERLAP: + g_object_set_property (G_OBJECT (priv->scaletempo), "overlap", value); + break; + case PROP_SEARCH: + g_object_set_property (G_OBJECT (priv->scaletempo), "search", value); + break; + case PROP_DISABLED:{ + gdouble rate = priv->rate; + gint pos = demo_player_get_position (player); + GstState end_state; + GstElement *new_sink; + + priv->is_disabled = g_value_get_boolean (value); + + g_debug ("Scaletempo: %s", priv->is_disabled ? "disabled" : "enabled"); + + end_state = + (GST_STATE (priv->pipeline) == + GST_STATE_PLAYING) ? GST_STATE_PLAYING : GST_STATE_PAUSED; + if (!_set_state_and_wait (player, GST_STATE_NULL, 10 * GST_SECOND, + "Unable to disable")) + break; + + new_sink = + (priv->is_disabled) ? priv->scalerate_line : priv->scaletempo_line; + g_object_set (G_OBJECT (priv->pipeline), "audio-sink", new_sink, NULL); + + if (pos > 0 || (rate && rate != 1.0)) { + _set_state_and_wait (player, GST_STATE_PAUSED, 10 * GST_SECOND, + "Unable to keep playback position and rate"); + _set_rate (player, rate, pos); + } + + gst_element_set_state (priv->pipeline, end_state); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +/* GTypeInfo functions */ +static void +demo_player_init (GTypeInstance * instance, gpointer klass) +{ + DemoPlayer *player = (DemoPlayer *) instance; + DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player); + priv->scaletempo = gst_element_factory_make ("scaletempo", "scaletempo"); + if (!priv->scaletempo) { + g_error ("Unable to make scaletempo element."); + } + priv->rate = 1.0; + priv->pipeline = NULL; + priv->ignore_state_change = FALSE; + priv->is_disabled = FALSE; +} + +static void +demo_player_class_init (gpointer klass, gpointer class_data) +{ + DemoPlayerClass *player_class = (DemoPlayerClass *) klass; + GObjectClass *as_object_class = G_OBJECT_CLASS (klass); + GType type; + + g_type_class_add_private (klass, sizeof (DemoPlayerPrivate)); + + /* DemoPlayer */ + player_class->scale_rate = demo_player_scale_rate_func; + player_class->set_rate = demo_player_set_rate_func; + player_class->load_uri = demo_player_load_uri_func; + player_class->play = demo_player_play_func; + player_class->pause = demo_player_pause_func; + player_class->seek_by = demo_player_seek_by_func; + player_class->seek_to = demo_player_seek_to_func; + player_class->get_position = demo_player_get_position_func; + player_class->get_duration = demo_player_get_duration_func; + + /* GObject */ + as_object_class->get_property = demo_player_get_property; + as_object_class->set_property = demo_player_set_property; + + /* Properties */ + g_object_class_install_property (as_object_class, PROP_RATE, + g_param_spec_double ("rate", "Rate", "Current playback rate", + -128, 128, 1.0, G_PARAM_READABLE)); + + g_object_class_install_property (as_object_class, PROP_STRIDE, + g_param_spec_uint ("stride", "Stride Length", + "Length in milliseconds to output each stride", 1, 10000, 60, + G_PARAM_READWRITE)); + + g_object_class_install_property (as_object_class, PROP_OVERLAP, + g_param_spec_double ("overlap", "Overlap Length", + "Percentage of stride to overlap", 0, 1, .2, G_PARAM_READWRITE)); + + g_object_class_install_property (as_object_class, PROP_SEARCH, + g_param_spec_uint ("search", "Search Length", + "Length in milliseconds to search for best overlap position", 0, + 10000, 14, G_PARAM_READWRITE)); + + g_object_class_install_property (as_object_class, PROP_DISABLED, + g_param_spec_boolean ("disabled", "disable scaletempo", + "Disable scaletempo and scale bothe tempo and pitch", FALSE, + G_PARAM_READWRITE)); + + /* Signals */ + type = G_TYPE_FROM_CLASS (klass); + demo_player_signals[SIGNAL_ERROR] = g_signal_new ("error", type, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + + demo_player_signals[SIGNAL_RATE_CHANGE] = g_signal_new ("rate-changed", type, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); + + demo_player_signals[SIGNAL_PLAYING_STARTED] = + g_signal_new ("playing-started", type, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + demo_player_signals[SIGNAL_PLAYING_PAUSED] = + g_signal_new ("playing-paused", type, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + demo_player_signals[SIGNAL_PLAYING_ENDED] = + g_signal_new ("playing-ended", type, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); +} + +GType +demo_player_get_type (void) +{ + static GType type = 0; + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo info = { + sizeof /* Class */ (DemoPlayerClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) demo_player_class_init, + (GClassFinalizeFunc) NULL, + (gconstpointer) NULL, /* class_data */ + sizeof /* Instance */ (DemoPlayer), + /* n_preallocs */ 0, + (GInstanceInitFunc) demo_player_init, + (const GTypeValueTable *) NULL + }; + type = g_type_register_static (G_TYPE_OBJECT, "DemoPlayer", &info, 0); + } + return type; +} |