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", ¤t_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