1 /**********************************************************
2  *
3  * mp3splt-gtk -- utility based on mp3splt,
4  *                for mp3/ogg splitting without decoding
5  *
6  * Copyright: (C) 2005-2014 Alexandru Munteanu
7  * Contact: m@ioalex.net
8  *
9  * from BMP to Audacious patch from Roberto Neri - 2007,2008
10  *
11  * http://mp3splt.sourceforge.net/
12  *
13  *********************************************************/
14 
15 /**********************************************************
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
30  * USA.
31  *
32  *********************************************************/
33 
34 /*!*******************************************************
35  * \file
36  * Control the gstreamer framework
37  *
38  * this file has functions to control the 'internal'
39  + gstreamer player
40  *********************************************************/
41 
42 #ifndef NO_GSTREAMER
43 
44 #include <gst/gst.h>
45 
46 #include "gstreamer_control.h"
47 
48 //! Send a call over the dbus
bus_call(GstBus * bus,GstMessage * msg,gpointer data)49 static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
50 {
51   ui_state *ui = (ui_state *) data;
52 
53   switch (GST_MESSAGE_TYPE(msg))
54   {
55     case GST_MESSAGE_ERROR:
56     {
57       gchar  *debug;
58       GError *error;
59 
60       gst_message_parse_error (msg, &error, &debug);
61       g_free(debug);
62 
63       gchar *message = NULL;
64       if (error->message != NULL)
65       {
66         gint malloc_size = strlen(error->message) + 20;
67         message = malloc(sizeof(char) * malloc_size);
68         if (message)
69         {
70           memset(message,'\0',malloc_size);
71           g_snprintf(message, malloc_size,_("gstreamer error: %s"),error->message);
72 
73           put_status_message_in_idle(message, ui);
74 
75           g_free(message);
76         }
77       }
78       g_error_free(error);
79       break;
80     }
81     case GST_MESSAGE_WARNING:
82     {
83       gchar  *debug;
84       GError *error;
85 
86       gst_message_parse_warning(msg, &error, &debug);
87       g_free(debug);
88 
89       gchar *message = NULL;
90       if (error->message != NULL)
91       {
92         gint malloc_size = strlen(error->message) + 20;
93         message = malloc(sizeof(char) * malloc_size);
94         if (message)
95         {
96           memset(message,'\0',malloc_size);
97           g_snprintf(message, malloc_size,_("Warning: %s"),error->message);
98 
99           put_status_message_in_idle(message, ui);
100 
101           g_free(message);
102         }
103       }
104       g_error_free (error);
105       break;
106     }
107     case GST_MESSAGE_INFO:
108     {
109       gchar  *debug;
110       GError *error;
111 
112       gst_message_parse_info(msg, &error, &debug);
113       g_free(debug);
114 
115       gchar *message = NULL;
116       if (error->message != NULL)
117       {
118         gint malloc_size = strlen(error->message) + 20;
119         message = malloc(sizeof(char) * malloc_size);
120         if (message)
121         {
122           memset(message,'\0',malloc_size);
123           g_snprintf(message, malloc_size,_("Info: %s"),error->message);
124 
125           put_status_message_in_idle(message, ui);
126 
127           g_free(message);
128         }
129       }
130       g_error_free (error);
131       break;
132     }
133     case GST_MESSAGE_TAG:
134     {
135       GstTagList *tag_list = NULL;
136       gst_message_parse_tag(msg, &tag_list);
137 
138       gint number_of_stream = 0;
139       g_object_get(ui->pi->play, "current-audio", &number_of_stream, NULL);
140 
141       //artist
142       const GValue *val = gst_tag_list_get_value_index(tag_list, GST_TAG_ARTIST,
143           number_of_stream);
144       if (val != NULL)
145       {
146         ui->pi->song_artist = g_value_get_string(val);
147       }
148 
149       //title
150       val = gst_tag_list_get_value_index(tag_list, GST_TAG_TITLE, number_of_stream);
151       if (val != NULL)
152       {
153         ui->pi->song_title = g_value_get_string(val);
154       }
155 
156       //rate (bps)
157       val = gst_tag_list_get_value_index(tag_list, GST_TAG_BITRATE, number_of_stream);
158       if (val != NULL)
159       {
160         ui->pi->rate = g_value_get_uint(val);
161       }
162 
163       break;
164     }
165     default:
166       break;
167   }
168 
169   return TRUE;
170 }
171 
172 //!Gets information about the song
gstreamer_get_song_infos(gchar * total_infos,ui_state * ui)173 void gstreamer_get_song_infos(gchar *total_infos, ui_state *ui)
174 {
175   if (!ui->pi->play)
176   {
177     return;
178   }
179 
180   gint freq = 0;
181   gint nch = 0;
182 
183   gint current_audio_stream = 0;
184   g_object_get(ui->pi->play, "current-audio", &current_audio_stream, NULL);
185 
186   gchar rate_str[32] = { '\0' };
187   gchar freq_str[32] = { '\0' };
188   gchar nch_str[32] = { '\0' };
189 
190   gchar *_Kbps = _("Kbps");
191   gchar *_Khz = _("Khz");
192 
193   GstCaps *caps = NULL;
194 
195   GstPad *pad = NULL;
196   g_signal_emit_by_name(ui->pi->play, "get-audio-pad", current_audio_stream, &pad);
197   if (pad)
198   {
199     caps = gst_pad_get_current_caps(pad);
200   }
201 
202   if (caps)
203   {
204     GstStructure *structure = NULL;
205     structure = gst_caps_get_structure(caps, 0);
206 
207     gst_structure_get_int(structure, "rate", &freq);
208     gst_structure_get_int(structure, "channels", &nch);
209 
210     gst_caps_unref(caps);
211 
212     g_snprintf(rate_str, 32, "%d", ui->pi->rate / 1000);
213     g_snprintf(freq_str, 32, "%d", freq / 1000);
214 
215     if (nch >= 2)
216     {
217       snprintf(nch_str, 32, "%s", _("stereo"));
218     }
219     else
220     {
221       snprintf(nch_str, 32, "%s", _("mono"));
222     }
223   }
224 
225   if (ui->pi->rate != 0)
226   {
227     g_snprintf(total_infos,512, "%s %s     %s %s    %s", rate_str,_Kbps,freq_str, _Khz,nch_str);
228   }
229   else
230   {
231     total_infos[0] = '\0';
232   }
233 }
234 
235 /*! returns the filename
236 
237 The result must be g_free'd after use.
238 */
gstreamer_get_filename(ui_state * ui)239 gchar *gstreamer_get_filename(ui_state *ui)
240 {
241   gchar *fname =  get_input_filename(ui->gui);
242   if (fname == NULL)
243   {
244     return NULL;
245   }
246 
247   return strdup(fname);
248 }
249 
250 //!returns the number of songs of the playlist
gstreamer_get_playlist_number(ui_state * ui)251 gint gstreamer_get_playlist_number(ui_state *ui)
252 {
253   return 1;
254 }
255 
256 /*!returns the title of the song
257 
258 The result must be g_free'd after use
259 */
gstreamer_get_title_song(ui_state * ui)260 gchar *gstreamer_get_title_song(ui_state *ui)
261 {
262   player_infos *pi = ui->pi;
263 
264   if (pi->song_artist || pi->song_title)
265   {
266     gint title_size = 20;
267 
268     if (pi->song_artist)
269     {
270       title_size += strlen(pi->song_artist);
271     }
272 
273     if (pi->song_title)
274     {
275       title_size += strlen(pi->song_title);
276     }
277 
278     gchar *title = malloc(sizeof(char) * title_size);
279     memset(title, '\0', title_size);
280 
281     if (pi->song_artist && pi->song_title)
282     {
283       g_snprintf(title, title_size, "%s - %s", pi->song_artist, pi->song_title);
284     }
285     else if (pi->song_title && !pi->song_artist)
286     {
287       g_snprintf(title, title_size, "%s", pi->song_title);
288     }
289     else if (pi->song_artist && !pi->song_title)
290     {
291       g_snprintf(title, title_size, "%s", pi->song_artist);
292     }
293 
294     return title;
295   }
296 
297   gchar *fname = gstreamer_get_filename(ui);
298   if (fname != NULL)
299   {
300     gchar *file = strrchr(fname, G_DIR_SEPARATOR);
301     if (file != NULL)
302     {
303       gchar *alloced_file = strdup(file+1);
304       g_free(fname);
305       fname = NULL;
306       return alloced_file;
307     }
308     else
309     {
310       return fname;
311     }
312   }
313   else
314   {
315     return strdup("-");
316   }
317 }
318 
319 //!returns elapsed time
gstreamer_get_time_elapsed(ui_state * ui)320 gint gstreamer_get_time_elapsed(ui_state *ui)
321 {
322   if (!ui->pi->play)
323   {
324     return 0;
325   }
326 
327   GstQuery *query = gst_query_new_position(GST_FORMAT_TIME);
328   gint64 time = 0;
329 
330   if (gst_element_query(ui->pi->play, query))
331   {
332     gst_query_parse_position(query, NULL, &time);
333   }
334 
335   gst_query_unref(query);
336 
337   return (gint) (time / GST_MSECOND);
338 }
339 
340 //!starts gstreamer
gstreamer_start(ui_state * ui)341 void gstreamer_start(ui_state *ui)
342 {
343   if (ui->pi->play)
344   {
345     gstreamer_quit(ui);
346     gst_object_unref(ui->pi->play);
347   }
348 
349   gst_init(NULL, NULL);
350 
351   ui->pi->play = gst_element_factory_make("playbin", "playbin");
352   if (!ui->pi->play)
353   {
354     put_status_message(_(" error: cannot create gstreamer playbin\n"), ui);
355     return;
356   }
357 
358   gtk_widget_show_all(ui->gui->playlist_box);
359 
360   ui->pi->_gstreamer_is_running = TRUE;
361   ui->pi->bus = gst_pipeline_get_bus(GST_PIPELINE(ui->pi->play));
362   gst_bus_add_watch(ui->pi->bus, bus_call, ui);
363   gst_object_unref(ui->pi->bus);
364 
365   //add the current filename
366   const gchar *fname =  get_input_filename(ui->gui);
367   GList *song_list = g_list_append(NULL, strdup(fname));
368   gstreamer_add_files(song_list, ui);
369   g_list_foreach(song_list, (GFunc)g_free, NULL);
370   g_list_free(song_list);
371 }
372 
373 //!selects the last file in the playlist
gstreamer_select_last_file(ui_state * ui)374 void gstreamer_select_last_file(ui_state *ui)
375 {
376 }
377 
378 //!plays the last file of the playlist
gstreamer_play_last_file(ui_state * ui)379 void gstreamer_play_last_file(ui_state *ui)
380 {
381   gstreamer_stop(ui);
382   gstreamer_play(ui);
383 }
384 
385 //!add files to the gstreamer playlist
gstreamer_add_files(GList * list,ui_state * ui)386 void gstreamer_add_files(GList *list, ui_state *ui)
387 {
388   player_infos *pi = ui->pi;
389 
390   if (pi->song_title) { pi->song_title = NULL; }
391   if (pi->song_artist) { pi->song_artist = NULL; }
392 
393   if (!ui->pi->play)
394   {
395     return;
396   }
397 
398   GstState state;
399   gst_element_get_state(ui->pi->play, &state, NULL, GST_CLOCK_TIME_NONE);
400   gst_element_set_state(ui->pi->play, GST_STATE_NULL);
401 
402   gint i = 0;
403   gchar *song = NULL;
404   while ((song = g_list_nth_data(list, i)) != NULL)
405   {
406     if (!song)
407     {
408       i++;
409       continue;
410     }
411 
412     add_playlist_file(song, ui);
413 
414     gchar *uri = g_filename_to_uri(song, NULL, NULL);
415     g_object_set(G_OBJECT(ui->pi->play), "uri", uri, NULL);
416     if (uri) { g_free(uri); }
417 
418     i++;
419   }
420 
421   if (state == GST_STATE_PLAYING)
422   {
423     gst_element_set_state(ui->pi->play, GST_STATE_PLAYING);
424   }
425   else if (state == GST_STATE_PAUSED)
426   {
427     gst_element_set_state(ui->pi->play, GST_STATE_PAUSED);
428   }
429 }
430 
431 //!sets volume
gstreamer_set_volume(gint volume,ui_state * ui)432 void gstreamer_set_volume(gint volume, ui_state *ui)
433 {
434 	if (ui->pi->play)
435 	{
436 		//values between 0 and 2
437 		//-documentation says values can be between 0 and 10
438 		g_object_set(G_OBJECT(ui->pi->play), "volume", (double) volume / 100.0 * 2, NULL);
439 	}
440 }
441 
442 //!returns volume
gstreamer_get_volume(ui_state * ui)443 gint gstreamer_get_volume(ui_state *ui)
444 {
445   if (!ui->pi->play)
446   {
447     return 0;
448   }
449 
450   //values between 0 and 2
451   //-documentation says values can be between 0 and 10
452   double volume = 0;
453   g_object_get(G_OBJECT(ui->pi->play), "volume", &volume, NULL);
454   return (gint) (volume / 2 * 100);
455 }
456 
457 //!starts gstreamer with songs
gstreamer_start_with_songs(GList * list,ui_state * ui)458 void gstreamer_start_with_songs(GList *list, ui_state *ui)
459 {
460   gstreamer_start(ui);
461   gstreamer_add_files(list, ui);
462   gstreamer_play(ui);
463 }
464 
465 //!returns TRUE if gstreamer is running; if not, FALSE
gstreamer_is_running(ui_state * ui)466 gint gstreamer_is_running(ui_state *ui)
467 {
468   return ui->pi->_gstreamer_is_running;
469 }
470 
471 //!returns TRUE if gstreamer is paused, if not, FALSE
gstreamer_is_paused(ui_state * ui)472 gint gstreamer_is_paused(ui_state *ui)
473 {
474   if (!ui->pi->play)
475   {
476     return FALSE;
477   }
478 
479   GstState state;
480   gst_element_get_state(ui->pi->play, &state, NULL, GST_CLOCK_TIME_NONE);
481 
482   if (state == GST_STATE_PAUSED)
483   {
484     return TRUE;
485   }
486 
487   return FALSE;
488 }
489 
490 //!plays a song
gstreamer_play(ui_state * ui)491 void gstreamer_play(ui_state *ui)
492 {
493   if (!ui->pi->play)
494   {
495     return;
496   }
497 
498   GstState state;
499   gst_element_get_state(ui->pi->play, &state, NULL, GST_CLOCK_TIME_NONE);
500   if (state == GST_STATE_PLAYING)
501   {
502     gstreamer_jump(0, ui);
503   }
504 
505   gst_element_set_state(ui->pi->play, GST_STATE_PLAYING);
506 }
507 
508 //!stops a song
gstreamer_stop(ui_state * ui)509 void gstreamer_stop(ui_state *ui)
510 {
511   if (!ui->pi->play)
512   {
513     return;
514   }
515 
516   gst_element_set_state(ui->pi->play, GST_STATE_NULL);
517 }
518 
519 //!pause a song
gstreamer_pause(ui_state * ui)520 void gstreamer_pause(ui_state *ui)
521 {
522   if (!ui->pi->play)
523   {
524     return;
525   }
526 
527   GstState state;
528   gst_element_get_state(ui->pi->play, &state, NULL, GST_CLOCK_TIME_NONE);
529 
530   if (state == GST_STATE_PLAYING)
531   {
532     //gint time = gstreamer_get_time_elapsed(ui);
533 
534     gst_element_set_state(ui->pi->play, GST_STATE_PAUSED);
535 
536     /*gst_element_seek(ui->pi->play,
537         1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
538         GST_SEEK_TYPE_SET, time * GST_MSECOND, 0, 0);*/
539     return;
540   }
541 
542   gstreamer_play(ui);
543 }
544 
545 //!changes to next song
gstreamer_next(ui_state * ui)546 void gstreamer_next(ui_state *ui)
547 {
548 }
549 
550 //!changes to previous song
gstreamer_prev(ui_state * ui)551 void gstreamer_prev(ui_state *ui)
552 {
553 }
554 
555 //!jump to time
gstreamer_jump(gint position,ui_state * ui)556 void gstreamer_jump(gint position, ui_state *ui)
557 {
558   if (!ui->pi->play)
559   {
560     return;
561   }
562 
563   gst_element_seek(ui->pi->play,
564       1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
565       GST_SEEK_TYPE_SET, position * GST_MSECOND, 0, 0);
566 }
567 
568 //!returns total time of the current song
gstreamer_get_total_time(ui_state * ui)569 gint gstreamer_get_total_time(ui_state *ui)
570 {
571   if (!ui->pi->play)
572   {
573     return 0;
574   }
575 
576   GstQuery *query = gst_query_new_duration(GST_FORMAT_TIME);
577   gint time = 0;
578 
579   if (gst_element_query(ui->pi->play, query))
580   {
581     gint64 total_time;
582     gst_query_parse_duration(query, NULL, &total_time);
583     time = (gint) (total_time / GST_MSECOND);
584   }
585 
586   gst_query_unref(query);
587 
588   return time;
589 }
590 
591 //!returns TRUE if gstreamer is playing, else FALSE
gstreamer_is_playing(ui_state * ui)592 gint gstreamer_is_playing(ui_state *ui)
593 {
594   if (!ui->pi->play)
595   {
596     return FALSE;
597   }
598 
599   GstState state;
600   gst_element_get_state(ui->pi->play, &state, NULL, GST_CLOCK_TIME_NONE);
601   if ((state == GST_STATE_PLAYING) || (state == GST_STATE_PAUSED))
602   {
603     return TRUE;
604   }
605 
606   return FALSE;
607 }
608 
609 //!quits player
gstreamer_quit(ui_state * ui)610 void gstreamer_quit(ui_state *ui)
611 {
612   if (ui->pi->play)
613   {
614     gst_element_set_state(ui->pi->play, GST_STATE_NULL);
615   }
616 
617   ui->pi->_gstreamer_is_running = FALSE;
618 }
619 
620 #endif
621 
622