No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2003 Jorn Baayen <jorn@nl.linux.org>
4 * Copyright (C) 2003,2004 Colin Walters <walters@debian.org>
5 * Copyright (C) 2009 Jonathan Matthew <jonathan@d14n.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * The Rhythmbox authors hereby grant permission for non-GPL compatible
13 * GStreamer plugins to be used and distributed together with GStreamer
14 * and Rhythmbox. This permission is above and beyond the permissions granted
15 * by the GPL license by which Rhythmbox is covered. If you modify this code
16 * you may extend this exception to your version of the code, but you are not
17 * obligated to do so. If you do not wish to do so, delete this exception
18 * statement from your version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 *
29 */
30
31 #include <config.h>
32 #include <math.h>
33 #include <string.h>
34 #include <stdlib.h>
35
36 #include <glib/gi18n.h>
37 #include <gdk/gdk.h>
38 #include <gst/tag/tag.h>
39 #include <gst/interfaces/streamvolume.h>
40 #include <gst/pbutils/pbutils.h>
41
42 #include "rb-debug.h"
43 #include "rb-marshal.h"
44 #include "rb-util.h"
45
46 #include "rb-player.h"
47 #include "rb-player-gst.h"
48 #include "rb-player-gst-helper.h"
49 #include "rb-player-gst-filter.h"
50 #include "rb-player-gst-tee.h"
51
52 static void rb_player_init (RBPlayerIface *iface);
53 static void rb_player_gst_filter_init (RBPlayerGstFilterIface *iface);
54 static void rb_player_gst_tee_init (RBPlayerGstTeeIface *iface);
55
56 static void state_change_finished (RBPlayerGst *mp, GError *error);
57
58 G_DEFINE_TYPE_WITH_CODE(RBPlayerGst, rb_player_gst, G_TYPE_OBJECT,
59 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER, rb_player_init)
60 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_FILTER, rb_player_gst_filter_init)
61 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_TEE, rb_player_gst_tee_init)
62 )
63
64 #define RB_PLAYER_GST_TICK_HZ 5
65 #define STATE_CHANGE_MESSAGE_TIMEOUT 5
66
67 enum
68 {
69 PROP_0,
70 PROP_PLAYBIN,
71 PROP_BUS
72 };
73
74 enum
75 {
76 PREPARE_SOURCE,
77 CAN_REUSE_STREAM,
78 REUSE_STREAM,
79 MISSING_PLUGINS,
80 LAST_SIGNAL
81 };
82
83 enum StateChangeAction {
84 DO_NOTHING,
85 PLAYER_SHUTDOWN,
86 SET_NEXT_URI,
87 STOP_TICK_TIMER,
88 FINISH_TRACK_CHANGE
89 };
90
91 static guint signals[LAST_SIGNAL] = { 0 };
92
93 struct _RBPlayerGstPrivate
94 {
95 char *prev_uri;
96 char *uri;
97 gpointer stream_data;
98 GDestroyNotify stream_data_destroy;
99 gpointer next_stream_data;
100 GDestroyNotify next_stream_data_destroy;
101
102 GstElement *playbin;
103 GstElement *audio_sink;
104 enum StateChangeAction state_change_action;
105
106 gboolean playing;
107 gboolean buffering;
108
109 gboolean stream_change_pending;
110 gboolean current_track_finishing;
111 gboolean playbin_stream_changing;
112 gboolean track_change;
113
114 gboolean emitted_error;
115
116 GList *stream_tags;
117
118 gint volume_changed;
119 gint volume_applied;
120 float cur_volume;
121
122 guint tick_timeout_id;
123
124 GList *waiting_tees;
125 GstElement *sinkbin;
126 GstElement *tee;
127
128 GList *waiting_filters; /* in reverse order */
129 GstElement *filterbin;
130 };
131
132 static void
133 _destroy_stream_data (RBPlayerGst *player)
134 {
135 if (player->priv->stream_data && player->priv->stream_data_destroy) {
136 player->priv->stream_data_destroy (player->priv->stream_data);
137 }
138 player->priv->stream_data = NULL;
139 player->priv->stream_data_destroy = NULL;
140 }
141
142 static void
143 _destroy_next_stream_data (RBPlayerGst *player)
144 {
145 if (player->priv->next_stream_data && player->priv->next_stream_data_destroy) {
146 player->priv->next_stream_data_destroy (player->priv->next_stream_data);
147 }
148 player->priv->next_stream_data = NULL;
149 player->priv->next_stream_data_destroy = NULL;
150 }
151
152 static void
153 about_to_finish_cb (GstElement *playbin, RBPlayerGst *player)
154 {
155 if (player->priv->stream_change_pending == TRUE) {
156 /* this probably shouldn't happen, but it's OK if it does, I think */
157 rb_debug ("got about-to-finish, but we already have a stream change pending.");
158 return;
159 }
160
161 /* don't handle about-to-finish for cdda */
162 if (g_str_has_prefix (player->priv->uri, "cdda://")) {
163 rb_debug ("ignoring about-to-finish for %s", player->priv->uri);
164 return;
165 }
166
167 /* emit EOS now and hope we get something to play */
168 player->priv->current_track_finishing = TRUE;
169
170 _rb_player_emit_eos (RB_PLAYER (player), player->priv->stream_data, TRUE);
171 }
172
173 static gboolean
174 emit_volume_changed_idle (RBPlayerGst *player)
175 {
176 double vol;
177
178 if (gst_element_implements_interface (player->priv->playbin, GST_TYPE_STREAM_VOLUME)) {
179 vol = gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->playbin),
180 GST_STREAM_VOLUME_FORMAT_CUBIC);
181 } else {
182 vol = player->priv->cur_volume;
183 }
184
185 _rb_player_emit_volume_changed (RB_PLAYER (player), vol);
186 return FALSE;
187 }
188
189 static void
190 volume_notify_cb (GObject *element, GstObject *prop_object, GParamSpec *pspec, RBPlayerGst *player)
191 {
192 gdouble v;
193 g_object_get (element, "volume", &v, NULL);
194 player->priv->cur_volume = v;
195
196 g_idle_add ((GSourceFunc) emit_volume_changed_idle, player);
197 }
198
199 static void
200 process_tag (const GstTagList *list, const gchar *tag, RBPlayerGst *player)
201 {
202 RBMetaDataField field;
203 GValue value = {0,};
204
205 /* process embedded images */
206 if (!g_strcmp0 (tag, GST_TAG_IMAGE) || !g_strcmp0 (tag, GST_TAG_PREVIEW_IMAGE)) {
207 GdkPixbuf *pixbuf;
208 pixbuf = rb_gst_process_embedded_image (list, tag);
209 if (pixbuf != NULL) {
210 _rb_player_emit_image (RB_PLAYER (player),
211 player->priv->stream_data,
212 pixbuf);
213 g_object_unref (pixbuf);
214 }
215 } else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
216 rb_debug ("emitting info field %d", field);
217 _rb_player_emit_info (RB_PLAYER (player),
218 player->priv->stream_data,
219 field,
220 &value);
221 g_value_unset (&value);
222 }
223 }
224
225 static void
226 emit_playing_stream_and_tags (RBPlayerGst *player, gboolean track_change)
227 {
228 GList *t;
229
230 if (track_change) {
231 /* swap stream data */
232 _destroy_stream_data (player);
233 player->priv->stream_data = player->priv->next_stream_data;
234 player->priv->stream_data_destroy = player->priv->next_stream_data_destroy;
235 player->priv->next_stream_data = NULL;
236 player->priv->next_stream_data_destroy = NULL;
237 }
238
239 _rb_player_emit_playing_stream (RB_PLAYER (player), player->priv->stream_data);
240
241 /* process any tag lists we received while starting the stream */
242 for (t = player->priv->stream_tags; t != NULL; t = t->next) {
243 GstTagList *tags;
244
245 tags = (GstTagList *)t->data;
246 rb_debug ("processing buffered taglist");
247 gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, player);
248 gst_tag_list_free (tags);
249 }
250 g_list_free (player->priv->stream_tags);
251 player->priv->stream_tags = NULL;
252 }
253
254 static void
255 handle_missing_plugin_message (RBPlayerGst *player, GstMessage *message)
256 {
257 char **details;
258 char **descriptions;
259 char *detail;
260 char *description;
261 int count;
262
263 rb_debug ("got missing-plugin message from %s: %s",
264 GST_OBJECT_NAME (GST_MESSAGE_SRC (message)),
265 gst_missing_plugin_message_get_installer_detail (message));
266
267 /* probably need to wait to collect any subsequent missing-plugin
268 * messages, but I think we'd need to wait for state changes to do
269 * that. for now, we can only handle a single message.
270 */
271 count = 1;
272
273 details = g_new0 (char *, count + 1);
274 descriptions = g_new0 (char *, count + 1);
275
276 detail = gst_missing_plugin_message_get_installer_detail (message);
277 description = gst_missing_plugin_message_get_description (message);
278 details[0] = g_strdup (detail);
279 descriptions[0] = g_strdup (description);
280
281 g_signal_emit (player, signals[MISSING_PLUGINS], 0, player->priv->stream_data, details, descriptions);
282 g_strfreev (details);
283 g_strfreev (descriptions);
284 }
285
286 static gboolean
287 tick_timeout (RBPlayerGst *mp)
288 {
289 if (mp->priv->playing) {
290 gint64 position;
291
292 position = rb_player_get_time (RB_PLAYER (mp));
293
294 /* if we don't have stream-changed messages, do the track change when
295 * the playback position is less than one second into the current track,
296 * which pretty much has to be the new one.
297 */
298 if (mp->priv->playbin_stream_changing && (position < GST_SECOND)) {
299 emit_playing_stream_and_tags (mp, TRUE);
300 mp->priv->playbin_stream_changing = FALSE;
301 }
302
303 _rb_player_emit_tick (RB_PLAYER (mp),
304 mp->priv->stream_data,
305 position,
306 -1);
307 }
308 return TRUE;
309 }
310
311 static void
312 set_playbin_volume (RBPlayerGst *player, float volume)
313 {
314 /* ignore the deep-notify we get directly from the sink, as it causes deadlock.
315 * we still get another one anyway.
316 */
317 g_signal_handlers_block_by_func (player->priv->playbin, volume_notify_cb, player);
318 if (gst_element_implements_interface (player->priv->playbin, GST_TYPE_STREAM_VOLUME))
319 gst_stream_volume_set_volume (GST_STREAM_VOLUME (player->priv->playbin),
320 GST_STREAM_VOLUME_FORMAT_CUBIC, volume);
321 else
322 g_object_set (player->priv->playbin, "volume", volume, NULL);
323 g_signal_handlers_unblock_by_func (player->priv->playbin, volume_notify_cb, player);
324 }
325
326
327
328 static void
329 track_change_done (RBPlayerGst *mp, GError *error)
330 {
331 mp->priv->stream_change_pending = FALSE;
332
333 if (error != NULL) {
334 rb_debug ("track change failed: %s", error->message);
335 return;
336 }
337 rb_debug ("track change finished");
338
339 mp->priv->current_track_finishing = FALSE;
340 mp->priv->buffering = FALSE;
341 mp->priv->playing = TRUE;
342
343 if (mp->priv->playbin_stream_changing == FALSE) {
344 emit_playing_stream_and_tags (mp, mp->priv->track_change);
345 }
346
347 if (mp->priv->tick_timeout_id == 0) {
348 mp->priv->tick_timeout_id =
349 g_timeout_add (1000 / RB_PLAYER_GST_TICK_HZ,
350 (GSourceFunc) tick_timeout,
351 mp);
352 }
353
354 if (mp->priv->volume_applied == 0) {
355 GstElement *e;
356
357 /* if the sink provides volume control, ignore the first
358 * volume setting, allowing the sink to restore its own
359 * volume.
360 */
361 e = rb_player_gst_find_element_with_property (mp->priv->audio_sink, "volume");
362 if (e != NULL) {
363 mp->priv->volume_applied = 1;
364 gst_object_unref (e);
365 }
366
367 if (mp->priv->volume_applied < mp->priv->volume_changed) {
368 rb_debug ("applying initial volume: %f", mp->priv->cur_volume);
369 set_playbin_volume (mp, mp->priv->cur_volume);
370 }
371
372 mp->priv->volume_applied = mp->priv->volume_changed;
373 }
374 }
375
376 static void
377 start_state_change (RBPlayerGst *mp, GstState state, enum StateChangeAction action)
378 {
379 GstStateChangeReturn scr;
380
381 rb_debug ("changing state to %s", gst_element_state_get_name (state));
382 mp->priv->state_change_action = action;
383 scr = gst_element_set_state (mp->priv->playbin, state);
384 if (scr == GST_STATE_CHANGE_SUCCESS) {
385 rb_debug ("state change succeeded synchronously");
386 state_change_finished (mp, NULL);
387 }
388 }
389
390 static void
391 state_change_finished (RBPlayerGst *mp, GError *error)
392 {
393 enum StateChangeAction action = mp->priv->state_change_action;
394 mp->priv->state_change_action = DO_NOTHING;
395
396 switch (action) {
397 case DO_NOTHING:
398 break;
399
400 case PLAYER_SHUTDOWN:
401 if (error != NULL) {
402 g_warning ("unable to shut down player pipeline: %s\n", error->message);
403 }
404 break;
405
406 case SET_NEXT_URI:
407 if (error != NULL) {
408 g_warning ("unable to stop playback: %s\n", error->message);
409 } else {
410 rb_debug ("setting new playback URI %s", mp->priv->uri);
411 g_object_set (mp->priv->playbin, "uri", mp->priv->uri, NULL);
412 start_state_change (mp, GST_STATE_PLAYING, FINISH_TRACK_CHANGE);
413 }
414 break;
415
416 case STOP_TICK_TIMER:
417 if (error != NULL) {
418 g_warning ("unable to pause playback: %s\n", error->message);
419 } else {
420 if (mp->priv->tick_timeout_id != 0) {
421 g_source_remove (mp->priv->tick_timeout_id);
422 mp->priv->tick_timeout_id = 0;
423 }
424 }
425 break;
426
427 case FINISH_TRACK_CHANGE:
428 track_change_done (mp, error);
429 break;
430 }
431 }
432
433 static gboolean
434 message_from_sink (GstElement *sink, GstMessage *message)
435 {
436 GstElement *src;
437 GstElement *match;
438 char *name;
439
440 src = GST_ELEMENT (GST_MESSAGE_SRC (message));
441
442 if (GST_IS_BIN (sink) == FALSE) {
443 return (src == sink);
444 }
445
446 name = gst_element_get_name (src);
447 match = gst_bin_get_by_name (GST_BIN (sink), name);
448 g_free (name);
449
450 if (match != NULL) {
451 g_object_unref (match);
452 return (match == src);
453 }
454
455 return FALSE;
456 }
457
458 static gboolean
459 bus_cb (GstBus *bus, GstMessage *message, RBPlayerGst *mp)
460 {
461 const GstStructure *structure;
462 g_return_val_if_fail (mp != NULL, FALSE);
463
464 switch (GST_MESSAGE_TYPE (message)) {
465 case GST_MESSAGE_ERROR: {
466 char *debug;
467 GError *error = NULL;
468 GError *sig_error = NULL;
469 int code;
470 gboolean emit = TRUE;
471
472 gst_message_parse_error (message, &error, &debug);
473
474 /* If we've already got an error, ignore 'internal data flow error'
475 * type messages, as they're too generic to be helpful.
476 */
477 if (mp->priv->emitted_error &&
478 error->domain == GST_STREAM_ERROR &&
479 error->code == GST_STREAM_ERROR_FAILED) {
480 rb_debug ("Ignoring generic error \"%s\"", error->message);
481 emit = FALSE;
482 }
483
484 code = rb_gst_error_get_error_code (error);
485
486 if (emit) {
487 if (message_from_sink (mp->priv->audio_sink, message)) {
488 rb_debug ("got error from sink: %s (%s)", error->message, debug);
489 /* Translators: the parameter here is an error message */
490 g_set_error (&sig_error,
491 RB_PLAYER_ERROR,
492 code,
493 _("Failed to open output device: %s"),
494 error->message);
495 } else {
496 rb_debug ("got error from stream: %s (%s)", error->message, debug);
497 g_set_error (&sig_error,
498 RB_PLAYER_ERROR,
499 code,
500 "%s",
501 error->message);
502 }
503 state_change_finished (mp, sig_error);
504 mp->priv->emitted_error = TRUE;
505 if (mp->priv->playbin_stream_changing) {
506 emit_playing_stream_and_tags (mp, TRUE);
507 }
508 _rb_player_emit_error (RB_PLAYER (mp), mp->priv->stream_data, sig_error);
509 }
510
511 /* close if not already closing */
512 if (mp->priv->uri != NULL)
513 rb_player_close (RB_PLAYER (mp), NULL, NULL);
514
515 g_error_free (error);
516 g_free (debug);
517 break;
518 }
519
520 case GST_MESSAGE_EOS:
521 _rb_player_emit_eos (RB_PLAYER (mp), mp->priv->stream_data, FALSE);
522 break;
523
524 case GST_MESSAGE_STATE_CHANGED:
525 {
526 GstState oldstate;
527 GstState newstate;
528 GstState pending;
529 gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
530 if (GST_MESSAGE_SRC (message) == GST_OBJECT (mp->priv->playbin)) {
531 if (pending == GST_STATE_VOID_PENDING) {
532 rb_debug ("playbin reached state %s", gst_element_state_get_name (newstate));
533 state_change_finished (mp, NULL);
534 }
535 }
536 break;
537 }
538
539 case GST_MESSAGE_TAG: {
540 GstTagList *tags;
541 gst_message_parse_tag (message, &tags);
542
543 if (mp->priv->stream_change_pending || mp->priv->playbin_stream_changing) {
544 mp->priv->stream_tags = g_list_append (mp->priv->stream_tags, tags);
545 } else {
546 gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, mp);
547 gst_tag_list_free (tags);
548 }
549 break;
550 }
551
552
553 case GST_MESSAGE_BUFFERING: {
554 gint progress;
555
556 structure = gst_message_get_structure (message);
557 if (!gst_structure_get_int (structure, "buffer-percent", &progress)) {
558 g_warning ("Could not get value from BUFFERING message");
559 break;
560 }
561
562 if (progress >= 100) {
563 mp->priv->buffering = FALSE;
564 if (mp->priv->playing) {
565 rb_debug ("buffering done, setting pipeline back to PLAYING");
566 gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING);
567 } else {
568 rb_debug ("buffering done, leaving pipeline PAUSED");
569 }
570 } else if (mp->priv->buffering == FALSE && mp->priv->playing) {
571
572 rb_debug ("buffering - temporarily pausing playback");
573 gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED);
574 mp->priv->buffering = TRUE;
575 }
576
577 _rb_player_emit_buffering (RB_PLAYER (mp), mp->priv->stream_data, progress);
578 break;
579 }
580
581 case GST_MESSAGE_APPLICATION:
582 structure = gst_message_get_structure (message);
583 _rb_player_emit_event (RB_PLAYER (mp), mp->priv->stream_data, gst_structure_get_name (structure), NULL);
584 break;
585
586 case GST_MESSAGE_ELEMENT:
587 structure = gst_message_get_structure (message);
588 if (gst_is_missing_plugin_message (message)) {
589 handle_missing_plugin_message (mp, message);
590 } else if (mp->priv->playbin_stream_changing &&
591 gst_structure_has_name (structure, "playbin2-stream-changed")) {
592 rb_debug ("got playbin2-stream-changed message");
593 mp->priv->playbin_stream_changing = FALSE;
594 emit_playing_stream_and_tags (mp, TRUE);
595 } else if (gst_structure_has_name (structure, "redirect")) {
596 const char *uri = gst_structure_get_string (structure, "new-location");
597 _rb_player_emit_redirect (RB_PLAYER (mp), mp->priv->stream_data, uri);
598 }
599 break;
600
601 default:
602 break;
603 }
604
605 /* emit message signals too, so plugins can process messages */
606 gst_bus_async_signal_func (bus, message, NULL);
607
608 return TRUE;
609 }
610
611 static void
612 source_notify_cb (GObject *object, GParamSpec *pspec, RBPlayerGst *player)
613 {
614 GstElement *source;
615
616 if (player->priv->uri == NULL) {
617 rb_debug ("got notify::source while changing to NULL");
618 return;
619 }
620
621 g_object_get (object, "source", &source, NULL);
622
623 g_signal_emit (player, signals[PREPARE_SOURCE], 0, player->priv->uri, source);
624
625 g_object_unref (source);
626 }
627
628 static gboolean
629 construct_pipeline (RBPlayerGst *mp, GError **error)
630 {
631 GstElement *sink;
632
633 mp->priv->playbin = gst_element_factory_make ("playbin2", NULL);
634 if (mp->priv->playbin == NULL) {
635 g_set_error (error,
636 RB_PLAYER_ERROR,
637 RB_PLAYER_ERROR_GENERAL,
638 _("Failed to create %s element; check your GStreamer installation"),
639 "playbin2");
640 return FALSE;
641 }
642 g_signal_connect_object (G_OBJECT (mp->priv->playbin),
643 "about-to-finish",
644 G_CALLBACK (about_to_finish_cb),
645 mp, 0);
646 g_signal_connect_object (G_OBJECT (mp->priv->playbin),
647 "deep-notify::volume",
648 G_CALLBACK (volume_notify_cb),
649 mp, 0);
650 g_signal_connect_object (G_OBJECT (mp->priv->playbin),
651 "notify::source",
652 G_CALLBACK (source_notify_cb),
653 mp, 0);
654
655 gst_bus_add_watch (gst_element_get_bus (mp->priv->playbin),
656 (GstBusFunc) bus_cb,
657 mp);
658
659 /* let plugins add bits to playbin */
660 g_object_notify (G_OBJECT (mp), "playbin");
661 g_object_notify (G_OBJECT (mp), "bus");
662
663 /* Use gsettingsaudiosink for audio if there's no audio sink yet */
664 g_object_get (mp->priv->playbin, "audio-sink", &mp->priv->audio_sink, NULL);
665 if (mp->priv->audio_sink == NULL) {
666 const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
667 int i;
668
669 for (i = 0; i < G_N_ELEMENTS (try_sinks); i++) {
670 mp->priv->audio_sink = rb_player_gst_try_audio_sink (try_sinks[i], NULL);
671 if (mp->priv->audio_sink != NULL) {
672 g_object_set (mp->priv->playbin, "audio-sink", mp->priv->audio_sink, NULL);
673 break;
674 }
675 }
676 if (mp->priv->audio_sink == NULL) {
677 g_set_error (error,
678 RB_PLAYER_ERROR,
679 RB_PLAYER_ERROR_GENERAL,
680 _("Failed to create %s element; check your GStreamer installation"),
681 "autoaudiosink");
682 return FALSE;
683 }
684 } else {
685 rb_debug ("existing audio sink found");
686 g_object_unref (mp->priv->audio_sink);
687 }
688
689 {
690 GstPad *pad;
691 GList *l;
692 GstElement *queue;
693 GstPad *ghostpad;
694
695 /* setup filterbin */
696 mp->priv->filterbin = rb_gst_create_filter_bin ();
697
698 /* set up the sinkbin with its tee element */
699 mp->priv->sinkbin = gst_bin_new (NULL);
700 mp->priv->tee = gst_element_factory_make ("tee", NULL);
701 queue = gst_element_factory_make ("queue", NULL);
702
703 /* link it all together and insert */
704 gst_bin_add_many (GST_BIN (mp->priv->sinkbin), mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);
705 gst_element_link_many (mp->priv->filterbin, mp->priv->tee, queue, mp->priv->audio_sink, NULL);
706
707 pad = gst_element_get_pad (mp->priv->filterbin, "sink");
708 ghostpad = gst_ghost_pad_new ("sink", pad);
709 gst_element_add_pad (mp->priv->sinkbin, ghostpad);
710 gst_object_unref (pad);
711
712 g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", mp->priv->sinkbin, NULL);
713
714 /* add any tees and filters that were waiting for us */
715 for (l = mp->priv->waiting_tees; l != NULL; l = g_list_next (l)) {
716 rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (mp), GST_ELEMENT (l->data));
717 }
718 g_list_free (mp->priv->waiting_tees);
719 mp->priv->waiting_tees = NULL;
720
721 for (l = mp->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
722 rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER(mp), GST_ELEMENT (l->data));
723 }
724 g_list_free (mp->priv->waiting_filters);
725 mp->priv->waiting_filters = NULL;
726 }
727
728 /* Use fakesink for video if there's no video sink yet */
729 g_object_get (mp->priv->playbin, "video-sink", &sink, NULL);
730 if (sink == NULL) {
731 sink = gst_element_factory_make ("fakesink", NULL);
732 g_object_set (mp->priv->playbin, "video-sink", sink, NULL);
733 } else {
734 g_object_unref (sink);
735 }
736
737 if (mp->priv->cur_volume > 1.0)
738 mp->priv->cur_volume = 1.0;
739 if (mp->priv->cur_volume < 0.0)
740 mp->priv->cur_volume = 0;
741
742 rb_debug ("pipeline construction complete");
743 return TRUE;
744 }
745
746 static gboolean
747 impl_close (RBPlayer *player, const char *uri, GError **error)
748 {
749 RBPlayerGst *mp = RB_PLAYER_GST (player);
750
751 if ((uri != NULL) && (mp->priv->uri != NULL) && strcmp (mp->priv->uri, uri) == 0) {
752 rb_debug ("URI doesn't match current playing URI; ignoring");
753 return TRUE;
754 }
755
756 mp->priv->playing = FALSE;
757 mp->priv->buffering = FALSE;
758 mp->priv->current_track_finishing = FALSE;
759
760 _destroy_stream_data (mp);
761 if (uri == NULL) {
762 _destroy_next_stream_data (mp);
763 }
764 g_free (mp->priv->uri);
765 g_free (mp->priv->prev_uri);
766 mp->priv->uri = NULL;
767 mp->priv->prev_uri = NULL;
768
769 if (mp->priv->tick_timeout_id != 0) {
770 g_source_remove (mp->priv->tick_timeout_id);
771 mp->priv->tick_timeout_id = 0;
772 }
773
774 if (mp->priv->playbin != NULL) {
775 start_state_change (mp, GST_STATE_NULL, PLAYER_SHUTDOWN);
776 }
777 return TRUE;
778 }
779
780 static gboolean
781 impl_open (RBPlayer *player,
782 const char *uri,
783 gpointer stream_data,
784 GDestroyNotify stream_data_destroy,
785 GError **error)
786 {
787 RBPlayerGst *mp = RB_PLAYER_GST (player);
788
789 if (mp->priv->playbin == NULL) {
790 if (!construct_pipeline (mp, error))
791 return FALSE;
792 }
793
794 g_assert (mp->priv->playbin != NULL);
795
796 if (uri == NULL) {
797 return impl_close (player, NULL, error);
798 }
799
800 rb_debug ("setting new uri to %s", uri);
801 _destroy_next_stream_data (mp);
802 g_free (mp->priv->prev_uri);
803 mp->priv->prev_uri = mp->priv->uri;
804 mp->priv->uri = g_strdup (uri);
805 mp->priv->next_stream_data = stream_data;
806 mp->priv->next_stream_data_destroy = stream_data_destroy;
807 mp->priv->emitted_error = FALSE;
808 mp->priv->stream_change_pending = TRUE;
809
810 return TRUE;
811 }
812
813 static gboolean
814 impl_opened (RBPlayer *player)
815 {
816 RBPlayerGst *mp = RB_PLAYER_GST (player);
817
818 return mp->priv->uri != NULL;
819 }
820
821 static gboolean
822 impl_play (RBPlayer *player, RBPlayerPlayType play_type, gint64 crossfade, GError **error)
823 {
824 RBPlayerGst *mp = RB_PLAYER_GST (player);
825
826 g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
827
828 mp->priv->track_change = TRUE;
829
830 if (mp->priv->stream_change_pending == FALSE) {
831 rb_debug ("no stream change pending, just restarting playback");
832 mp->priv->track_change = FALSE;
833 start_state_change (mp, GST_STATE_PLAYING, FINISH_TRACK_CHANGE);
834 } else if (mp->priv->current_track_finishing) {
835 rb_debug ("current track finishing -> just setting URI on playbin");
836 g_object_set (mp->priv->playbin, "uri", mp->priv->uri, NULL);
837
838 mp->priv->playbin_stream_changing = TRUE;
839
840 track_change_done (mp, NULL);
841 } else {
842 gboolean reused = FALSE;
843
844 /* try to reuse the stream */
845 if (mp->priv->prev_uri != NULL) {
846 g_signal_emit (mp,
847 signals[CAN_REUSE_STREAM], 0,
848 mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin,
849 &reused);
850
851 if (reused) {
852 rb_debug ("reusing stream to switch from %s to %s", mp->priv->prev_uri, mp->priv->uri);
853 g_signal_emit (player,
854 signals[REUSE_STREAM], 0,
855 mp->priv->uri, mp->priv->prev_uri, mp->priv->playbin);
856 track_change_done (mp, *error);
857 }
858 }
859
860 /* no stream reuse, so stop, set the new URI, then start */
861 if (reused == FALSE) {
862 rb_debug ("not in transition, stopping current track to start the new one");
863 start_state_change (mp, GST_STATE_READY, SET_NEXT_URI);
864 }
865
866 }
867
868 return TRUE;
869 }
870
871 static void
872 impl_pause (RBPlayer *player)
873 {
874 RBPlayerGst *mp = RB_PLAYER_GST (player);
875
876 if (!mp->priv->playing)
877 return;
878
879 mp->priv->playing = FALSE;
880
881 g_return_if_fail (mp->priv->playbin != NULL);
882
883 start_state_change (mp, GST_STATE_PAUSED, STOP_TICK_TIMER);
884 }
885
886 static gboolean
887 impl_playing (RBPlayer *player)
888 {
889 RBPlayerGst *mp = RB_PLAYER_GST (player);
890
891 return mp->priv->playing;
892 }
893
894 static void
895 impl_set_volume (RBPlayer *player,
896 float volume)
897 {
898 RBPlayerGst *mp = RB_PLAYER_GST (player);
899 g_return_if_fail (volume >= 0.0 && volume <= 1.0);
900
901 mp->priv->volume_changed++;
902 if (mp->priv->volume_applied > 0) {
903 set_playbin_volume (mp, volume);
904 mp->priv->volume_applied = mp->priv->volume_changed;
905 } else {
906 /* volume will be applied in the first call to impl_play */
907 }
908
909 mp->priv->cur_volume = volume;
910 }
911
912 static float
913 impl_get_volume (RBPlayer *player)
914 {
915 RBPlayerGst *mp = RB_PLAYER_GST (player);
916
917 return mp->priv->cur_volume;
918 }
919
920 static gboolean
921 impl_seekable (RBPlayer *player)
922 {
923 RBPlayerGst *mp = RB_PLAYER_GST (player);
924 gboolean can_seek = TRUE;
925 GstQuery *query;
926
927 if (mp->priv->playbin == NULL)
928 return FALSE;
929
930 query = gst_query_new_seeking (GST_FORMAT_TIME);
931 if (gst_element_query (mp->priv->playbin, query)) {
932 gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL);
933 } else {
934 gst_query_unref (query);
935
936 query = gst_query_new_duration (GST_FORMAT_TIME);
937 can_seek = gst_element_query (mp->priv->playbin, query);
938 }
939 gst_query_unref (query);
940
941 return can_seek;
942 }
943
944 static void
945 impl_set_time (RBPlayer *player, gint64 time)
946 {
947 RBPlayerGst *mp = RB_PLAYER_GST (player);
948
949 rb_debug ("seeking to %" G_GINT64_FORMAT, time);
950 gst_element_seek (mp->priv->playbin, 1.0,
951 GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
952 GST_SEEK_TYPE_SET, time,
953 GST_SEEK_TYPE_NONE, -1);
954
955 gst_element_get_state (mp->priv->playbin, NULL, NULL, 100 * GST_MSECOND);
956 }
957
958 static gint64
959 impl_get_time (RBPlayer *player)
960 {
961 RBPlayerGst *mp = RB_PLAYER_GST (player);
962
963 if (mp->priv->playbin != NULL) {
964 gint64 position = -1;
965 GstFormat fmt = GST_FORMAT_TIME;
966
967 gst_element_query_position (mp->priv->playbin, &fmt, &position);
968 return position;
969 } else {
970 return -1;
971 }
972 }
973
974 static gboolean
975 need_pad_blocking (RBPlayerGst *mp)
976 {
977 return (mp->priv->playing || (mp->priv->uri != NULL));
978 }
979
980 static gboolean
981 impl_add_tee (RBPlayerGstTee *player, GstElement *element)
982 {
983 RBPlayerGst *mp = RB_PLAYER_GST (player);
984
985 if (mp->priv->tee == NULL) {
986 mp->priv->waiting_tees = g_list_prepend (mp->priv->waiting_tees, element);
987 return TRUE;
988 }
989
990 return rb_gst_add_tee (RB_PLAYER (player), mp->priv->tee, element, need_pad_blocking (mp));
991 }
992
993 static gboolean
994 impl_remove_tee (RBPlayerGstTee *player, GstElement *element)
995 {
996 RBPlayerGst *mp = RB_PLAYER_GST (player);
997
998 if (mp->priv->tee == NULL) {
999 gst_object_sink (element);
1000 mp->priv->waiting_tees = g_list_remove (mp->priv->waiting_tees, element);
1001 return TRUE;
1002 }
1003
1004 return rb_gst_remove_tee (RB_PLAYER (mp), mp->priv->tee, element, need_pad_blocking (mp));
1005 }
1006
1007 static gboolean
1008 impl_add_filter (RBPlayerGstFilter *player, GstElement *element)
1009 {
1010 RBPlayerGst *mp = RB_PLAYER_GST (player);
1011
1012 if (mp->priv->filterbin == NULL) {
1013 mp->priv->waiting_filters = g_list_prepend (mp->priv->waiting_filters, element);
1014 return TRUE;
1015 }
1016 return rb_gst_add_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp));
1017 }
1018
1019 static gboolean
1020 impl_remove_filter (RBPlayerGstFilter *player, GstElement *element)
1021 {
1022 RBPlayerGst *mp = RB_PLAYER_GST (player);
1023
1024 if (mp->priv->filterbin == NULL) {
1025 gst_object_sink (element);
1026 mp->priv->waiting_filters = g_list_remove (mp->priv->waiting_filters, element);
1027 return TRUE;
1028 }
1029
1030 return rb_gst_remove_filter (RB_PLAYER (mp), mp->priv->filterbin, element, need_pad_blocking (mp));
1031 }
1032
1033 static void
1034 rb_player_gst_filter_init (RBPlayerGstFilterIface *iface)
1035 {
1036 iface->add_filter = impl_add_filter;
1037 iface->remove_filter = impl_remove_filter;
1038 }
1039
1040 static void
1041 rb_player_gst_tee_init (RBPlayerGstTeeIface *iface)
1042 {
1043 iface->add_tee = impl_add_tee;
1044 iface->remove_tee = impl_remove_tee;
1045 }
1046
1047
1048
1049 RBPlayer *
1050 rb_player_gst_new (GError **error)
1051 {
1052 return RB_PLAYER (g_object_new (RB_TYPE_PLAYER_GST, NULL, NULL));
1053 }
1054
1055
1056 static void
1057 rb_player_gst_init (RBPlayerGst *mp)
1058 {
1059 mp->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((mp),
1060 RB_TYPE_PLAYER_GST,
1061 RBPlayerGstPrivate));
1062 }
1063
1064 static void
1065 impl_get_property (GObject *object,
1066 guint prop_id,
1067 GValue *value,
1068 GParamSpec *pspec)
1069 {
1070 RBPlayerGst *mp = RB_PLAYER_GST (object);
1071
1072 switch (prop_id) {
1073 case PROP_PLAYBIN:
1074 g_value_set_object (value, mp->priv->playbin);
1075 break;
1076 case PROP_BUS:
1077 if (mp->priv->playbin) {
1078 GstBus *bus;
1079 bus = gst_element_get_bus (mp->priv->playbin);
1080 g_value_set_object (value, bus);
1081 gst_object_unref (bus);
1082 }
1083 break;
1084 default:
1085 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1086 break;
1087 }
1088 }
1089
1090 static void
1091 impl_set_property (GObject *object,
1092 guint prop_id,
1093 const GValue *value,
1094 GParamSpec *pspec)
1095 {
1096 /*RBPlayerGst *mp = RB_PLAYER_GST (object);*/
1097
1098 switch (prop_id) {
1099 default:
1100 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1101 break;
1102 }
1103 }
1104
1105 static void
1106 impl_dispose (GObject *object)
1107 {
1108 RBPlayerGst *mp;
1109
1110 mp = RB_PLAYER_GST (object);
1111
1112 if (mp->priv->tick_timeout_id != 0) {
1113 g_source_remove (mp->priv->tick_timeout_id);
1114 mp->priv->tick_timeout_id = 0;
1115 }
1116
1117 if (mp->priv->playbin != NULL) {
1118 gst_element_set_state (mp->priv->playbin, GST_STATE_NULL);
1119 g_object_unref (mp->priv->playbin);
1120 mp->priv->playbin = NULL;
1121 mp->priv->audio_sink = NULL;
1122 }
1123
1124 if (mp->priv->waiting_tees != NULL) {
1125 g_list_foreach (mp->priv->waiting_tees, (GFunc)gst_object_sink, NULL);
1126 g_list_free (mp->priv->waiting_tees);
1127 mp->priv->waiting_tees = NULL;
1128 }
1129
1130 if (mp->priv->waiting_filters != NULL) {
1131 g_list_foreach (mp->priv->waiting_filters, (GFunc)gst_object_sink, NULL);
1132 g_list_free (mp->priv->waiting_filters);
1133 mp->priv->waiting_filters = NULL;
1134 }
1135
1136 G_OBJECT_CLASS (rb_player_gst_parent_class)->dispose (object);
1137 }
1138
1139 static void
1140 rb_player_init (RBPlayerIface *iface)
1141 {
1142 iface->open = impl_open;
1143 iface->opened = impl_opened;
1144 iface->close = impl_close;
1145 iface->play = impl_play;
1146 iface->pause = impl_pause;
1147 iface->playing = impl_playing;
1148 iface->set_volume = impl_set_volume;
1149 iface->get_volume = impl_get_volume;
1150 iface->seekable = impl_seekable;
1151 iface->set_time = impl_set_time;
1152 iface->get_time = impl_get_time;
1153 iface->multiple_open = (RBPlayerFeatureFunc) rb_false_function;
1154 }
1155
1156 static void
1157 rb_player_gst_class_init (RBPlayerGstClass *klass)
1158 {
1159 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1160
1161 object_class->dispose = impl_dispose;
1162 object_class->get_property = impl_get_property;
1163 object_class->set_property = impl_set_property;
1164
1165 g_object_class_install_property (object_class,
1166 PROP_PLAYBIN,
1167 g_param_spec_object ("playbin",
1168 "playbin",
1169 "playbin element",
1170 GST_TYPE_ELEMENT,
1171 G_PARAM_READABLE));
1172 g_object_class_install_property (object_class,
1173 PROP_BUS,
1174 g_param_spec_object ("bus",
1175 "bus",
1176 "GStreamer message bus",
1177 GST_TYPE_BUS,
1178 G_PARAM_READABLE));
1179
1180 signals[PREPARE_SOURCE] =
1181 g_signal_new ("prepare-source",
1182 G_OBJECT_CLASS_TYPE (object_class),
1183 G_SIGNAL_RUN_LAST,
1184 G_STRUCT_OFFSET (RBPlayerGstClass, prepare_source),
1185 NULL, NULL,
1186 rb_marshal_VOID__STRING_OBJECT,
1187 G_TYPE_NONE,
1188 2,
1189 G_TYPE_STRING, GST_TYPE_ELEMENT);
1190 signals[CAN_REUSE_STREAM] =
1191 g_signal_new ("can-reuse-stream",
1192 G_OBJECT_CLASS_TYPE (object_class),
1193 G_SIGNAL_RUN_LAST,
1194 G_STRUCT_OFFSET (RBPlayerGstClass, can_reuse_stream),
1195 NULL, NULL,
1196 rb_marshal_BOOLEAN__STRING_STRING_OBJECT,
1197 G_TYPE_BOOLEAN,
1198 3,
1199 G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
1200 signals[REUSE_STREAM] =
1201 g_signal_new ("reuse-stream",
1202 G_OBJECT_CLASS_TYPE (object_class),
1203 G_SIGNAL_RUN_LAST,
1204 G_STRUCT_OFFSET (RBPlayerGstClass, reuse_stream),
1205 NULL, NULL,
1206 rb_marshal_VOID__STRING_STRING_OBJECT,
1207 G_TYPE_NONE,
1208 3,
1209 G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
1210 signals[MISSING_PLUGINS] =
1211 g_signal_new ("missing-plugins",
1212 G_OBJECT_CLASS_TYPE (object_class),
1213 G_SIGNAL_RUN_LAST,
1214 0, /* no point handling this internally */
1215 NULL, NULL,
1216 rb_marshal_VOID__POINTER_POINTER_POINTER,
1217 G_TYPE_NONE,
1218 3,
1219 G_TYPE_POINTER, G_TYPE_STRV, G_TYPE_STRV);
1220
1221 g_type_class_add_private (klass, sizeof (RBPlayerGstPrivate));
1222 }