2 * Gnome Simple Stateful Music Player
3 * Copyright (C) 2007 Andy Balaam
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.
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
20 #include "gssmp_gstreamer.h"
24 #define PROGRESS_TIMEOUT_LENGTH 1000
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
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
[])
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
;
61 bus
= gst_pipeline_get_bus (GST_PIPELINE (play
));
64 gst_bus_add_watch (bus
, bus_callback
, NULL
);
68 fprintf (stderr
, _("Unable to make the gstreamer pipeline bus.\n"));
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
))
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
);
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
)
138 nanos
= secs
* GST_SECOND
;
140 if (!gst_element_seek(GST_ELEMENT(play
), 1.0, GST_FORMAT_TIME
,
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
;
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);
183 case GST_MESSAGE_NEW_CLOCK
:
185 internal_duration_callback ();
186 if ((stored_start_offset
> 0))
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
,
194 GST_SEEK_TYPE_SET
, real_offset
,
195 GST_SEEK_TYPE_NONE
, GST_CLOCK_TIME_NONE
))
197 internal_progress_callback ();
201 fprintf (stderr
, _("Seek failed!\n"));
206 case GST_MESSAGE_CLOCK_PROVIDE
:
208 internal_duration_callback ();
211 case GST_MESSAGE_DURATION
:
213 internal_duration_callback ();
216 case GST_MESSAGE_EOS
:
218 if (external_eos_callback
)
220 external_eos_callback ();
224 case GST_MESSAGE_ERROR
:
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
);
239 case GST_MESSAGE_WARNING
:
243 gst_message_parse_warning (message
, &gerror
, NULL
);
244 fprintf ( stderr
, _("gstreamer warning: %s\n"), gerror
->message
);
246 g_error_free (gerror
);
249 case GST_MESSAGE_STATE_CHANGED
:
250 case GST_MESSAGE_STATE_DIRTY
:
251 case GST_MESSAGE_CLOCK_LOST
:
253 // Ignore - not particularly interesting
258 fprintf( stderr
, _("Ignored a '%s' message from gstreamer.\n"),
259 GST_MESSAGE_TYPE_NAME(message
) );
267 void internal_tag_callback_uint (const GstTagList
*tag_list
, const gchar
* tag
)
271 if (gst_tag_list_get_uint (tag_list
, tag
, &value
) && external_tag_callback
)
275 snprintf (svalue
, 50, "%d", value
);
276 external_tag_callback (tag
, svalue
);
280 void internal_tag_callback (const GstTagList
*tag_list
, const gchar
* tag
)
285 if (gst_tag_list_get_string (tag_list
, tag
, &value
) && external_tag_callback
)
287 external_tag_callback (tag
, value
);
293 gboolean
internal_progress_callback ()
296 gst_element_get_state (play
, &stt
, NULL
, GST_CLOCK_TIME_NONE
);
298 if (stt
== GST_STATE_PLAYING
)
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
);
312 fprintf (stderr
, "Failed to query position\n" );
319 gboolean
internal_duration_callback ()
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
334 fprintf (stderr, "Failed to query duration\n" );
340 // -----------------------------------------
342 void test_dump_tag (const GstTagList
*list
, const gchar
*tag
, gpointer
347 type
= gst_tag_get_type (tag
);
354 if (gst_tag_list_get_int (list
, tag
, &value
))
356 printf ("tag: %s -> %d (int)\n", tag
, value
);
360 printf ("tag: %s -> NOTHING INT\n", tag
);
367 if (gst_tag_list_get_uint (list
, tag
, &value
))
369 printf ("tag: %s -> %d (uint)\n", tag
, value
);
373 printf ("tag: %s -> NOTHING INT\n", tag
);
380 if (gst_tag_list_get_long (list
, tag
, &value
))
382 printf ("tag: %s -> %ld (long)\n", tag
, value
);
386 printf ("tag: %s -> NOTHING INT\n", tag
);
393 if (gst_tag_list_get_ulong (list
, tag
, &value
))
395 printf ("tag: %s -> %ld (ulong)\n", tag
, value
);
399 printf ("tag: %s -> NOTHING INT\n", tag
);
406 if (gst_tag_list_get_string (list
, tag
, &value
))
408 printf ("tag: %s -> %s\n", tag
, value
);
413 printf ("tag: %s -> NOTHING STRING\n", tag
);
419 printf ("tag: %s -> UNKNOWN\n", tag
);