Correct GError* code to use the correct free function.
[gssmp.git] / src / gssmp_gstreamer.c
blob901f9397f4a0247440c27ac7b57286c5b84d855b
1 /*
2 * Gnome Simple Stateful Music Player
3 * Copyright (C) 2007 Andy Balaam
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 **/
20 #include "gssmp_gstreamer.h"
22 #include <gst/gst.h>
24 #define PROGRESS_TIMEOUT_LENGTH 1000
26 GstElement *play;
28 gboolean bus_callback (GstBus *bus, GstMessage *message, gpointer data);
29 void internal_tag_callback ( const GstTagList *tag_list, const gchar* tag );
30 void internal_tag_callback_uint (const GstTagList *tag_list, const gchar* tag);
31 gboolean internal_progress_callback ();
32 gboolean internal_duration_callback ();
33 void test_dump_tag (const GstTagList *list, const gchar *tag, gpointer
34 user_data);
36 void (*external_duration_callback)(gint secs);
37 void (*external_progress_callback)(gint secs);
38 void (*external_tag_callback)(const gchar* tag, const gchar* value);
39 void (*external_eos_callback)();
40 void (*external_error_callback)(const gchar* message);
42 gint stored_start_offset;
43 gboolean something_playing;
45 void gssmp_gstreamer_init (int argc, char *argv[])
47 GstElement* fakesink;
49 gst_init (&argc, &argv);
50 play = gst_element_factory_make ("playbin", "play");
51 fakesink = gst_element_factory_make ("fakesink", "sink");
53 // Suppress video output
54 g_object_set (play, "video-sink", fakesink, NULL);
56 something_playing = FALSE;
58 if (play)
60 GstBus* bus;
61 bus = gst_pipeline_get_bus (GST_PIPELINE (play));
62 if (bus)
64 gst_bus_add_watch (bus, bus_callback, NULL);
66 else
68 fprintf (stderr, _("Unable to make the gstreamer pipeline bus.\n"));
71 else
73 fprintf (stderr, _("Unable to make the gstreamer playbin.\n"));
76 g_timeout_add (PROGRESS_TIMEOUT_LENGTH, internal_progress_callback, NULL);
78 external_duration_callback = NULL;
79 external_progress_callback = NULL;
80 external_tag_callback = NULL;
81 external_eos_callback = NULL;
82 external_error_callback = NULL;
85 void gssmp_gstreamer_quit ()
87 gst_element_set_state (play, GST_STATE_NULL);
88 gst_object_unref (GST_OBJECT (play));
91 void gssmp_gstreamer_play (const gchar* filename, const gint start_offset,
92 void (*duration_callback)(gint secs),
93 void (*progress_callback)(gint secs),
94 void (*tag_callback)(const gchar* tag, const gchar* value),
95 void (*eos_callback)(), void (*error_callback)(const gchar* message))
97 gchar* uri;
99 stored_start_offset = start_offset;
101 external_duration_callback = duration_callback;
102 external_progress_callback = progress_callback;
103 external_tag_callback = tag_callback;
104 external_eos_callback = eos_callback;
105 external_error_callback = error_callback;
107 gst_element_set_state (play, GST_STATE_READY);
109 uri = g_strconcat ("file://", filename, NULL);
111 g_object_set (G_OBJECT (play), "uri", uri, NULL);
112 something_playing = TRUE;
114 gst_element_set_state (play, GST_STATE_PLAYING);
116 g_free (uri);
119 void gssmp_gstreamer_unpause ()
121 if (something_playing)
123 gst_element_set_state (play, GST_STATE_PLAYING);
127 void gssmp_gstreamer_pause ()
129 if (something_playing)
131 gst_element_set_state (play, GST_STATE_PAUSED);
135 void gssmp_gstreamer_seek (gint secs)
137 gint64 nanos;
138 nanos = secs * GST_SECOND;
140 if (!gst_element_seek(GST_ELEMENT(play), 1.0, GST_FORMAT_TIME,
141 GST_SEEK_FLAG_FLUSH,
142 GST_SEEK_TYPE_SET, nanos,
143 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ))
145 fprintf (stderr, _("Seek failed!\n"));
149 void gssmp_gstreamer_set_volume (gdouble value)
151 g_object_set( G_OBJECT(play), "volume", value, NULL );
154 // --------------------------------
156 gboolean bus_callback (GstBus *bus, GstMessage *message, gpointer data)
158 switch( message->type )
160 case GST_MESSAGE_TAG:
162 const gchar *message_type_name;
163 GstTagList *tag_list;
165 tag_list = NULL;
167 message_type_name = gst_message_type_get_name (message->type);
169 gst_message_parse_tag (message, &tag_list);
171 internal_tag_callback (tag_list, "title");
172 internal_tag_callback (tag_list, "artist");
173 internal_tag_callback (tag_list, "album");
174 internal_tag_callback_uint (tag_list, "track-number");
175 internal_tag_callback_uint (tag_list, "track-count");
177 // For debugging tags:
178 //gst_tag_list_foreach (tag_list, (GstTagForeachFunc)test_dump_tag, NULL);
180 g_free (tag_list);
181 break;
183 case GST_MESSAGE_NEW_CLOCK:
185 internal_duration_callback ();
186 if ((stored_start_offset > 0))
188 gint64 real_offset;
189 real_offset = stored_start_offset * GST_SECOND;
190 stored_start_offset = 0;
192 if (gst_element_seek(GST_ELEMENT(play), 1.0, GST_FORMAT_TIME,
193 GST_SEEK_FLAG_FLUSH,
194 GST_SEEK_TYPE_SET, real_offset,
195 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE ))
197 internal_progress_callback ();
199 else
201 fprintf (stderr, _("Seek failed!\n"));
204 break;
206 case GST_MESSAGE_CLOCK_PROVIDE:
208 internal_duration_callback ();
209 break;
211 case GST_MESSAGE_DURATION:
213 internal_duration_callback ();
214 break;
216 case GST_MESSAGE_EOS:
218 if (external_eos_callback)
220 external_eos_callback ();
222 break;
224 case GST_MESSAGE_ERROR:
226 GError* gerror;
228 gst_message_parse_error (message, &gerror, NULL);
229 fprintf (stderr, _("gstreamer error: %s\n"), gerror->message );
231 gst_element_set_state (play, GST_STATE_NULL);
232 something_playing = FALSE;
234 external_error_callback (gerror->message);
236 g_error_free (gerror);
237 break;
239 case GST_MESSAGE_WARNING:
241 GError* gerror;
243 gst_message_parse_warning (message, &gerror, NULL);
244 fprintf ( stderr, _("gstreamer warning: %s\n"), gerror->message );
246 g_error_free (gerror);
247 break;
249 case GST_MESSAGE_STATE_CHANGED:
250 case GST_MESSAGE_STATE_DIRTY:
251 case GST_MESSAGE_CLOCK_LOST:
253 // Ignore - not particularly interesting
254 break;
256 default:
258 fprintf( stderr, _("Ignored a '%s' message from gstreamer.\n"),
259 GST_MESSAGE_TYPE_NAME(message) );
260 break;
264 return TRUE;
267 void internal_tag_callback_uint (const GstTagList *tag_list, const gchar* tag)
269 uint value;
271 if (gst_tag_list_get_uint (tag_list, tag, &value) && external_tag_callback)
273 char svalue[50];
275 snprintf (svalue, 50, "%d", value);
276 external_tag_callback (tag, svalue);
280 void internal_tag_callback (const GstTagList *tag_list, const gchar* tag)
282 gchar* value;
284 value = NULL;
285 if (gst_tag_list_get_string (tag_list, tag, &value) && external_tag_callback)
287 external_tag_callback (tag, value);
289 g_free (value);
293 gboolean internal_progress_callback ()
295 GstState stt;
296 gst_element_get_state (play, &stt, NULL, GST_CLOCK_TIME_NONE);
298 if (stt == GST_STATE_PLAYING)
300 gint64 nanos;
301 gint secs;
302 static GstFormat format = GST_FORMAT_TIME;
304 if (gst_element_query_position (play, &format, &nanos )
305 && external_progress_callback)
307 secs = nanos / GST_SECOND;
308 external_progress_callback (secs);
310 else
312 fprintf (stderr, "Failed to query position\n" );
316 return TRUE;
319 gboolean internal_duration_callback ()
321 gint64 nanos;
322 gint secs;
323 static GstFormat format = GST_FORMAT_TIME;
325 if (gst_element_query_duration (play, &format, &nanos )
326 && external_duration_callback)
328 secs = nanos / GST_SECOND;
329 external_duration_callback (secs);
331 /* Fails quite often - presumably nothing to worry about
332 else
334 fprintf (stderr, "Failed to query duration\n" );
337 return TRUE;
340 // -----------------------------------------
342 void test_dump_tag (const GstTagList *list, const gchar *tag, gpointer
343 user_data)
345 GType type;
347 type = gst_tag_get_type (tag);
349 switch (type)
351 case G_TYPE_INT:
353 int value;
354 if (gst_tag_list_get_int (list, tag, &value))
356 printf ("tag: %s -> %d (int)\n", tag, value);
358 else
360 printf ("tag: %s -> NOTHING INT\n", tag);
362 break;
364 case G_TYPE_UINT:
366 uint value;
367 if (gst_tag_list_get_uint (list, tag, &value))
369 printf ("tag: %s -> %d (uint)\n", tag, value);
371 else
373 printf ("tag: %s -> NOTHING INT\n", tag);
375 break;
377 case G_TYPE_LONG:
379 long value;
380 if (gst_tag_list_get_long (list, tag, &value))
382 printf ("tag: %s -> %ld (long)\n", tag, value);
384 else
386 printf ("tag: %s -> NOTHING INT\n", tag);
388 break;
390 case G_TYPE_ULONG:
392 ulong value;
393 if (gst_tag_list_get_ulong (list, tag, &value))
395 printf ("tag: %s -> %ld (ulong)\n", tag, value);
397 else
399 printf ("tag: %s -> NOTHING INT\n", tag);
401 break;
403 case G_TYPE_STRING:
405 gchar* value;
406 if (gst_tag_list_get_string (list, tag, &value))
408 printf ("tag: %s -> %s\n", tag, value);
409 g_free (value);
411 else
413 printf ("tag: %s -> NOTHING STRING\n", tag);
415 break;
417 default:
419 printf ("tag: %s -> UNKNOWN\n", tag);
420 break;