Add controls to disable scaletempo
[gst-scaletempo-demo-rj.git] / src / demo-player.c
blob5b6b8cd06f9fedaadaeeca8b3d9c5c45f32a47ae
1 /* demo-player.c
2 * Copyright (C) 2008 Rov Juvano <rovjuvano@users.sourceforge.net>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "demo-player.h"
19 #include "gst/gst.h"
21 #undef G_LOG_DOMAIN
22 #define G_LOG_DOMAIN "demo-player"
24 enum
26 SIGNAL_ERROR,
27 SIGNAL_RATE_CHANGE,
28 SIGNAL_PLAYING_STARTED,
29 SIGNAL_PLAYING_PAUSED,
30 SIGNAL_PLAYING_ENDED,
31 LAST_SIGNAL
33 static guint demo_player_signals[LAST_SIGNAL] = { 0 };
35 enum
37 PROP_0,
38 PROP_RATE,
39 PROP_STRIDE,
40 PROP_OVERLAP,
41 PROP_SEARCH,
42 PROP_DISABLED
45 typedef struct _DemoPlayerPrivate
47 gdouble rate;
48 GstElement *scaletempo;
49 GstElement *pipeline;
50 gboolean is_disabled;
51 GstElement *scaletempo_line;
52 GstElement *scalerate_line;
53 gboolean ignore_state_change;
54 } DemoPlayerPrivate;
56 #define DEMO_PLAYER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEMO_TYPE_PLAYER, DemoPlayerPrivate))
59 static gboolean
60 no_pipeline (DemoPlayer *player)
62 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
63 if (!priv->pipeline) {
64 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "No media loaded");
65 return TRUE;
67 return FALSE;
70 static gboolean
71 demo_player_event_listener (GstElement *host,
72 GstEvent *event,
73 gpointer data)
75 DemoPlayer *player = DEMO_PLAYER (data);
76 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
78 if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
79 gdouble rate, applied_rate;
80 gst_event_parse_new_segment_full (event, NULL, &rate, &applied_rate, NULL, NULL, NULL, NULL);
81 gdouble new_rate = rate * applied_rate;
82 if (priv->rate != new_rate) {
83 priv->rate = new_rate;
84 g_signal_emit (player, demo_player_signals[SIGNAL_RATE_CHANGE], 0, new_rate);
88 return TRUE;
91 static void
92 demo_player_state_changed_cb (GstBus *bus,
93 GstMessage *message,
94 gpointer data)
96 DemoPlayer *player = DEMO_PLAYER (data);
97 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
99 if ( GST_ELEMENT (GST_MESSAGE_SRC (message)) != priv->pipeline )
100 return;
102 GstState old, new, pending;
103 gst_message_parse_state_changed (message, &old, &new, &pending);
105 if (pending == GST_STATE_VOID_PENDING) {
106 if (priv->ignore_state_change) {
107 priv->ignore_state_change = FALSE;
108 } else if (new == GST_STATE_PAUSED) {
109 g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_PAUSED], 0);
110 } else if (new == GST_STATE_PLAYING) {
111 g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_STARTED], 0);
116 static void
117 demo_player_eos_cb (GstBus *bus,
118 GstMessage *message,
119 gpointer data)
121 DemoPlayer *player = DEMO_PLAYER (data);
122 g_signal_emit (player, demo_player_signals[SIGNAL_PLAYING_ENDED], 0);
125 #define MAKE_ELEMENT(line, var, type, name) \
126 if ( !(var = gst_element_factory_make (type, name) ) ) { \
127 g_print ("element could not be created: %s/%s\n", type, name); \
128 return; \
130 if (line) gst_bin_add (GST_BIN (line), var);
132 #define LINK_ELEMENTS(src, sink) \
133 if (!gst_element_link (src, sink)) { \
134 g_warning ("Failed to link elements: %s -> %s", \
135 GST_ELEMENT_NAME (src), GST_ELEMENT_NAME (sink) ); \
136 return; \
139 static void
140 demo_player_build_pipeline (DemoPlayer *player)
142 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
143 priv->pipeline = NULL;
144 if (!priv->scaletempo) {
145 return;
147 GstElement *filter = priv->scaletempo;
149 GstElement *playbin, *vsink;
151 MAKE_ELEMENT (NULL, playbin, "playbin", "playbin");
153 GstPlugin *gconf = gst_default_registry_find_plugin ("gconfelements");
154 gboolean has_gconf = (gconf != NULL);
155 gst_object_unref (gconf);
157 if (has_gconf) {
158 MAKE_ELEMENT (NULL, vsink, "gconfvideosink", "vsink");
159 g_object_set (G_OBJECT (playbin), "video_sink", vsink, NULL);
161 const gchar *audiosink_name = has_gconf ? "gconfaudiosink" : "autoaudiosink";
163 GstElement *audioline = gst_bin_new ("audioline");
164 GstElement *format, *resample, *asink;
165 gst_bin_add (GST_BIN (audioline), filter);
166 MAKE_ELEMENT (audioline, format, "audioconvert", "format");
167 MAKE_ELEMENT (audioline, resample, "audioresample", "resample");
168 MAKE_ELEMENT (audioline, asink, audiosink_name, "audio_sink");
169 LINK_ELEMENTS (filter, format);
170 LINK_ELEMENTS (format, resample);
171 LINK_ELEMENTS (resample, asink);
173 gst_pad_add_event_probe (gst_element_get_pad (asink, "sink"), G_CALLBACK (demo_player_event_listener), player);
175 GstPad *ghostpad = gst_element_get_pad (filter, "sink");
176 gst_element_add_pad (audioline, gst_ghost_pad_new ("sink", ghostpad));
177 gst_object_unref (ghostpad);
178 g_object_set (G_OBJECT (playbin), "audio-sink", audioline, NULL);
180 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
181 gst_bus_add_signal_watch (bus);
182 g_signal_connect (bus, "message::state-changed", G_CALLBACK (demo_player_state_changed_cb), player);
183 g_signal_connect (bus, "message::eos", G_CALLBACK (demo_player_eos_cb), player);
184 gst_object_unref (bus);
186 priv->scaletempo = filter;
187 priv->pipeline = playbin;
189 priv->scaletempo_line = audioline;
190 MAKE_ELEMENT (NULL, priv->scalerate_line, "gconfaudiosink", "scaling_audio_sink");
191 gst_pad_add_event_probe (gst_element_get_pad (priv->scalerate_line, "sink"),
192 G_CALLBACK (demo_player_event_listener), player);
193 g_object_ref (priv->scaletempo_line);
194 g_object_ref (priv->scalerate_line);
198 /* method implementations */
199 static void
200 _set_rate (DemoPlayer *player,
201 gdouble new_rate,
202 gint second)
204 if (new_rate == 0) {
205 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Cannot set playback to zero. Pausing instead.");
206 demo_player_pause (player);
209 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
211 gint64 pos;
212 GstSeekType seek_type;
213 if (second < 0) {
214 GstFormat fmt = GST_FORMAT_TIME;
215 seek_type = GST_SEEK_TYPE_SET;
216 if ( !gst_element_query_position (priv->pipeline, &fmt, &pos) ) {
217 // This should be the default but too many upstream elements seek anyway
218 pos = GST_CLOCK_TIME_NONE;
219 seek_type = GST_SEEK_TYPE_NONE;
221 } else {
222 seek_type = GST_SEEK_TYPE_SET;
223 pos = second * GST_SECOND;
226 if (!gst_element_seek (priv->pipeline, new_rate,
227 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
228 seek_type, pos,
229 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
230 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Unable to change playback rate");
231 } else {
232 priv->ignore_state_change = TRUE;
236 static void
237 demo_player_scale_rate_func (DemoPlayer *player,
238 gdouble scale)
240 if (no_pipeline (player)) return;
242 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
244 if (scale != 1.0) {
245 g_message ("Scaling Rate by: %3.2f", scale);
246 _set_rate (player, priv->rate * scale, -1);
250 static void
251 demo_player_set_rate_func (DemoPlayer *player,
252 gdouble new_rate)
254 if (no_pipeline (player)) return;
256 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
258 if (priv->rate != new_rate) {
259 g_message ("Setting Rate to: %3.2f", new_rate);
260 _set_rate (player, new_rate, -1);
264 static gboolean
265 _set_state_and_wait (DemoPlayer *player,
266 GstState new_state,
267 GstClockTime timeout,
268 const gchar* error_msg)
270 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
271 GstStateChangeReturn ret = gst_element_set_state (priv->pipeline, new_state);
272 if (ret == GST_STATE_CHANGE_ASYNC) {
273 ret = gst_element_get_state (priv->pipeline, NULL, NULL, timeout);
275 if (ret != GST_STATE_CHANGE_SUCCESS) {
276 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, error_msg);
277 return FALSE;
279 return TRUE;
282 static void
283 demo_player_load_uri_func (DemoPlayer *player,
284 gchar *uri)
286 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
287 if (!priv->pipeline) {
288 demo_player_build_pipeline (player);
289 if (!priv->pipeline) {
290 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Could not build player");
291 return;
294 if (!g_str_has_prefix (uri, "file:///")) {
295 GError *err = NULL;
296 if (g_path_is_absolute (uri)) {
297 uri = g_filename_to_uri (uri, NULL, &err);
298 } else {
299 gchar *curdir = g_get_current_dir ();
300 gchar *absolute_path = g_strconcat (curdir, G_DIR_SEPARATOR_S, uri, NULL);
301 uri = g_filename_to_uri (absolute_path, NULL, &err);
302 g_free (absolute_path);
303 g_free (curdir);
305 if (err) {
306 gchar *msg = g_strconcat ("Could not load uri: ", err->message, NULL);
307 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, msg);
308 return;
312 g_message ("Loading URI: %s", uri);
314 GstState end_state = (GST_STATE (priv->pipeline) == GST_STATE_PLAYING) ? GST_STATE_PLAYING : GST_STATE_PAUSED;
315 if (!_set_state_and_wait (player, GST_STATE_NULL, 10 * GST_SECOND, "Unable to load uri"))
316 return;
318 g_object_set (G_OBJECT (priv->pipeline), "uri", uri, NULL);
320 gdouble rate = priv->rate;
321 if (rate && rate != 1.0) {
322 _set_state_and_wait (player, GST_STATE_PAUSED, 10 * GST_SECOND, "Unable to keep playback rate");
323 _set_rate (player, rate, -1);
326 gst_element_set_state (priv->pipeline, end_state);
329 static void
330 demo_player_play_func (DemoPlayer *player)
332 if (no_pipeline (player)) return;
334 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
336 if (GST_STATE (priv->pipeline) == GST_STATE_PLAYING) {
337 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Already playing");
338 return;
341 g_debug ("Starting to Play");
342 GstStateChangeReturn ret = gst_element_set_state (priv->pipeline, GST_STATE_PLAYING);
343 if (ret == GST_STATE_CHANGE_FAILURE) {
344 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Unable to start playback");
345 return;
349 static void
350 demo_player_pause_func (DemoPlayer *player)
352 if (no_pipeline (player)) return;
354 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
356 if (GST_STATE (priv->pipeline) == GST_STATE_PAUSED) {
357 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Already paused");
358 return;
361 g_debug ("Starting to Pause");
362 GstStateChangeReturn ret = gst_element_set_state (priv->pipeline, GST_STATE_PAUSED);
363 if (ret == GST_STATE_CHANGE_FAILURE) {
364 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Unable to pause playback");
365 return;
369 static void
370 _seek_to (DemoPlayer *player,
371 gint new_second)
373 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
374 if (!gst_element_seek (priv->pipeline, priv->rate,
375 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
376 GST_SEEK_TYPE_SET, new_second * GST_SECOND,
377 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
378 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek failed");
379 return;
382 priv->ignore_state_change = TRUE;
385 static void
386 demo_player_seek_by_func (DemoPlayer *player,
387 gint seconds)
389 if (no_pipeline (player)) return;
391 g_debug ("Seeking by: %i", seconds);
393 gint pos = demo_player_get_position (player);
394 if (pos < 0) {
395 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek-by failed: could not determine position");
396 return;
399 _seek_to (player, MAX (0, pos + seconds));
402 static void
403 demo_player_seek_to_func (DemoPlayer *player,
404 gint second)
406 if (no_pipeline (player)) return;
408 g_debug ("Seeking to: %i", second);
410 gint new_second;
412 if (second < 0) {
413 gint dur = demo_player_get_duration (player);
414 if (dur < 0) {
415 g_signal_emit (player, demo_player_signals[SIGNAL_ERROR], 0, "Seek-to failed: could not determine duration");
416 return;
418 new_second = MAX (0, dur + second);
419 } else {
420 new_second = second;
423 _seek_to (player, new_second);
426 static gint
427 demo_player_get_position_func (DemoPlayer *player)
429 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
430 if (!priv->pipeline) return -1;
432 gint64 pos;
433 GstFormat fmt = GST_FORMAT_TIME;
434 if ( !gst_element_query_position (priv->pipeline, &fmt, &pos) || pos < 0) {
435 return -1;
438 return (gint)(pos / GST_SECOND);
441 static gint
442 demo_player_get_duration_func (DemoPlayer *player)
444 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
445 if (!priv->pipeline) return -1;
447 gint64 dur;
448 GstFormat fmt = GST_FORMAT_TIME;
449 if ( !gst_element_query_duration (priv->pipeline, &fmt, &dur) || dur < 0) {
450 return -1;
453 return (gint)(dur / GST_SECOND);
457 /* Method wrappers */
458 void
459 demo_player_scale_rate (DemoPlayer *player,
460 gdouble scale)
462 g_return_if_fail (DEMO_IS_PLAYER (player));
464 DEMO_PLAYER_GET_CLASS (player)->scale_rate (player, scale);
467 void
468 demo_player_set_rate (DemoPlayer *player,
469 gdouble new_rate)
471 g_return_if_fail (DEMO_IS_PLAYER (player));
473 DEMO_PLAYER_GET_CLASS (player)->set_rate (player, new_rate);
476 void
477 demo_player_load_uri (DemoPlayer *player,
478 gchar *uri)
480 g_return_if_fail (DEMO_IS_PLAYER (player));
482 DEMO_PLAYER_GET_CLASS (player)->load_uri (player, uri);
485 void
486 demo_player_play (DemoPlayer *player)
488 g_return_if_fail (DEMO_IS_PLAYER (player));
490 DEMO_PLAYER_GET_CLASS (player)->play (player);
493 void
494 demo_player_pause (DemoPlayer *player)
496 g_return_if_fail (DEMO_IS_PLAYER (player));
498 DEMO_PLAYER_GET_CLASS (player)->pause (player);
501 void
502 demo_player_seek_by (DemoPlayer *player,
503 gint seconds)
505 g_return_if_fail (DEMO_IS_PLAYER (player));
507 DEMO_PLAYER_GET_CLASS (player)->seek_by (player, seconds);
510 void
511 demo_player_seek_to (DemoPlayer *player,
512 gint second)
514 g_return_if_fail (DEMO_IS_PLAYER (player));
516 DEMO_PLAYER_GET_CLASS (player)->seek_to (player, second);
519 gint
520 demo_player_get_position (DemoPlayer *player)
522 g_return_val_if_fail (DEMO_IS_PLAYER (player), -1);
524 return DEMO_PLAYER_GET_CLASS (player)->get_position (player);
527 gint
528 demo_player_get_duration (DemoPlayer *player)
530 g_return_val_if_fail (DEMO_IS_PLAYER (player), -1);
532 return DEMO_PLAYER_GET_CLASS (player)->get_duration (player);
535 /* GObject overrides */
536 static void
537 demo_player_get_property (GObject *object,
538 guint property_id,
539 GValue *value,
540 GParamSpec *pspec)
542 DemoPlayer *player = DEMO_PLAYER (object);
543 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
544 switch (property_id) {
545 case PROP_RATE:
546 g_value_set_double (value, priv->rate);
547 break;
548 case PROP_STRIDE:
549 g_object_get_property (G_OBJECT (priv->scaletempo), "stride", value);
550 break;
551 case PROP_OVERLAP:
552 g_object_get_property (G_OBJECT (priv->scaletempo), "overlap", value);
553 break;
554 case PROP_SEARCH:
555 g_object_get_property (G_OBJECT (priv->scaletempo), "search", value);
556 break;
557 case PROP_DISABLED:
558 g_value_set_boolean (value, priv->is_disabled);
559 break;
560 default:
561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
562 break;
566 static void
567 demo_player_set_property (GObject *object,
568 guint property_id,
569 const GValue *value,
570 GParamSpec *pspec)
572 DemoPlayer *player = DEMO_PLAYER (object);
573 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
574 switch (property_id) {
575 case PROP_STRIDE:
576 g_object_set_property (G_OBJECT (priv->scaletempo), "stride", value);
577 break;
578 case PROP_OVERLAP:
579 g_object_set_property (G_OBJECT (priv->scaletempo), "overlap", value);
580 break;
581 case PROP_SEARCH:
582 g_object_set_property (G_OBJECT (priv->scaletempo), "search", value);
583 break;
584 case PROP_DISABLED: {
585 priv->is_disabled = g_value_get_boolean (value);
586 g_debug ("Scaletempo: %s", priv->is_disabled ? "disabled" : "enabled");
588 gdouble rate = priv->rate;
589 gint pos = demo_player_get_position (player);
591 GstState end_state = (GST_STATE (priv->pipeline) == GST_STATE_PLAYING) ? GST_STATE_PLAYING : GST_STATE_PAUSED;
592 if (!_set_state_and_wait (player, GST_STATE_NULL, 10 * GST_SECOND, "Unable to disable"))
593 break;
595 GstElement *new_sink = (priv->is_disabled) ? priv->scalerate_line : priv->scaletempo_line;
596 g_object_set (G_OBJECT (priv->pipeline), "audio-sink", new_sink, NULL);
598 if (pos > 0 || (rate && rate != 1.0)) {
599 _set_state_and_wait (player, GST_STATE_PAUSED, 10 * GST_SECOND, "Unable to keep playback position and rate");
600 _set_rate (player, rate, pos);
603 gst_element_set_state (priv->pipeline, end_state);
604 break;
606 default:
607 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
608 break;
613 /* GTypeInfo functions */
614 static void
615 demo_player_init (GTypeInstance *instance,
616 gpointer klass)
618 DemoPlayer *player = (DemoPlayer *)instance;
619 DemoPlayerPrivate *priv = DEMO_PLAYER_GET_PRIVATE (player);
620 priv->scaletempo = gst_element_factory_make ("scaletempo", "scaletempo");
621 if (!priv->scaletempo) {
622 g_error ("Unable to make scaletempo element.");
624 priv->rate = 1.0;
625 priv->pipeline = NULL;
626 priv->ignore_state_change = FALSE;
627 priv->is_disabled = FALSE;
630 static void
631 demo_player_class_init (gpointer klass,
632 gpointer class_data)
634 g_type_class_add_private (klass, sizeof (DemoPlayerPrivate));
636 /* DemoPlayer */
637 DemoPlayerClass *player_class = (DemoPlayerClass *)klass;
638 player_class->scale_rate = demo_player_scale_rate_func;
639 player_class->set_rate = demo_player_set_rate_func;
640 player_class->load_uri = demo_player_load_uri_func;
641 player_class->play = demo_player_play_func;
642 player_class->pause = demo_player_pause_func;
643 player_class->seek_by = demo_player_seek_by_func;
644 player_class->seek_to = demo_player_seek_to_func;
645 player_class->get_position = demo_player_get_position_func;
646 player_class->get_duration = demo_player_get_duration_func;
648 /* GObject */
649 GObjectClass *as_object_class = G_OBJECT_CLASS (klass);
650 as_object_class->get_property = demo_player_get_property;
651 as_object_class->set_property = demo_player_set_property;
653 /* Properties */
654 g_object_class_install_property (as_object_class, PROP_RATE,
655 g_param_spec_double ("rate", "Rate", "Current playback rate",
656 -128, 128, 1.0, G_PARAM_READABLE));
658 g_object_class_install_property (as_object_class , PROP_STRIDE,
659 g_param_spec_uint ("stride", "Stride Length", "Length in milliseconds to output each stride",
660 1, 10000, 60, G_PARAM_READWRITE));
662 g_object_class_install_property (as_object_class , PROP_OVERLAP,
663 g_param_spec_double ("overlap", "Overlap Length", "Percentage of stride to overlap",
664 0, 1, .2, G_PARAM_READWRITE));
666 g_object_class_install_property (as_object_class , PROP_SEARCH,
667 g_param_spec_uint ("search", "Search Length", "Length in milliseconds to search for best overlap position",
668 0, 10000, 14, G_PARAM_READWRITE));
670 g_object_class_install_property (as_object_class , PROP_DISABLED,
671 g_param_spec_boolean ("disabled", "disable scaletempo", "Disable scaletempo and scale bothe tempo and pitch",
672 FALSE, G_PARAM_READWRITE));
674 /* Signals */
675 GType type = G_TYPE_FROM_CLASS (klass);
676 demo_player_signals[SIGNAL_ERROR] = g_signal_new ("error", type,
677 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
678 g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
680 demo_player_signals[SIGNAL_RATE_CHANGE] = g_signal_new ("rate-changed", type,
681 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
682 g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE);
684 demo_player_signals[SIGNAL_PLAYING_STARTED] = g_signal_new ("playing-started", type,
685 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
686 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
688 demo_player_signals[SIGNAL_PLAYING_PAUSED] = g_signal_new ("playing-paused", type,
689 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
690 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
692 demo_player_signals[SIGNAL_PLAYING_ENDED] = g_signal_new ("playing-ended", type,
693 G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
694 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
697 GType
698 demo_player_get_type (void)
700 static GType type = 0;
701 if (G_UNLIKELY (type == 0)) {
702 static const GTypeInfo info = {
703 sizeof /* Class */ (DemoPlayerClass),
704 (GBaseInitFunc) NULL,
705 (GBaseFinalizeFunc) NULL,
706 (GClassInitFunc) demo_player_class_init,
707 (GClassFinalizeFunc) NULL,
708 (gconstpointer) NULL, /* class_data */
709 sizeof /* Instance */ (DemoPlayer),
710 /* n_preallocs */ 0,
711 (GInstanceInitFunc) demo_player_init,
712 (const GTypeValueTable *) NULL
714 type = g_type_register_static (G_TYPE_OBJECT, "DemoPlayer", &info, 0);
716 return type;