No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2006,2010 Jonathan Matthew <jonathan@d14n.org>
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 * The Rhythmbox authors hereby grant permission for non-GPL compatible
11 * GStreamer plugins to be used and distributed together with GStreamer
12 * and Rhythmbox. This permission is above and beyond the permissions granted
13 * by the GPL license by which Rhythmbox is covered. If you modify this code
14 * you may extend this exception to your version of the code, but you are not
15 * obligated to do so. If you do not wish to do so, delete this exception
16 * statement from your version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
29 /*
30 * GStreamer player backend with crossfading and gaplessness and trees and
31 * flowers and bunnies.
32 */
33
34 /*
35 * basic design:
36 *
37 * we have a single output bin, beginning with an adder.
38 * connected to this are a number of stream bins, consisting of a
39 * source, decodebin2, audio convert/resample, and a volume element used
40 * for fading in and out. (might be interesting to replace those with
41 * high/low pass filter elements?)
42 *
43 * stream bins only stay connected to the adder while actually playing.
44 * when not playing (prerolling or paused), the stream bin's source pad
45 * is blocked so no data can flow.
46 *
47 * streams go through a number of states:
48 *
49 * when a stream is created (in rb_player_open()), it starts in PREROLLING
50 * state. from there:
51 *
52 * - rb_player_play(): -> PREROLL_PLAY
53 * - preroll finishes: -> WAITING
54 *
55 * from WAITING:
56 *
57 * - rb_player_play(), _AFTER_EOS, other stream playing: -> WAITING_EOS
58 * - rb_player_play(), _CROSSFADE, other stream playing: -> FADING IN, link to adder, unblock
59 * + fade out existing stream
60 * - rb_player_play(), _REPLACE, other stream playing: -> PLAYING, link to adder, unblock
61 * + stop existing stream
62 * - rb_player_play(), existing stream paused: -> PLAYING, link to adder, unblock
63 * + stop existing stream
64 * - rb_player_play(), nothing already playing: -> PLAYING, link to adder, unblock
65 *
66 * from PREROLL_PLAY:
67 *
68 * - preroll finishes, _AFTER_EOS, other stream playing: -> WAITING_EOS
69 * - preroll finishes, _CROSSFADE, other stream playing: -> FADING_IN, link to adder, unblock
70 * + fade out existing stream
71 * - preroll finishes, _REPLACE, other stream playing: -> PLAYING, link to adder, unblock
72 * + stop existing stream
73 * - preroll finishes, existing stream paused: -> PLAYING, link to adder, unblock
74 * + stop existing stream
75 * - preroll finishes, nothing already playing: -> PLAYING, link to adder, unblock
76 *
77 * from WAITING_EOS:
78 *
79 * - EOS received for another stream: -> PLAYING, link to adder, unblock
80 *
81 * from FADING_IN:
82 *
83 * - fade in completes: -> PLAYING
84 * - another stream starts fading in: -> FADING_OUT
85 * - rb_player_pause(): -> PAUSED, block, unlink from adder
86 * - stopped for another stream: -> PENDING_REMOVE
87 * - rb_player_set_time(): -> SEEKING, block, unlink
88 * - reused for another stream: -> REUSING; block, unlink
89 *
90 * from PLAYING:
91 *
92 * - rb_player_pause(): -> FADING_OUT_PAUSE, fade out (short fade)
93 * - EOS: -> PENDING_REMOVE
94 * - another stream starts fading in: -> FADING_OUT
95 * - stopped for another stream: -> PENDING_REMOVE
96 * - rb_player_set_time(): -> SEEKING, block, unlink
97 * - reused for another stream: -> REUSING; block, unlink
98 *
99 * from SEEKING:
100 * - rb_player_pause(): -> SEEKING_PAUSED
101 * - blocked: perform seek, link, unblock -> PLAYING | FADING_IN
102 *
103 * from SEEKING_PAUSED:
104 * - blocked: perform seek, -> PAUSED
105 * - rb_player_play(): -> SEEKING
106 *
107 * from PAUSED:
108 *
109 * - rb_player_play(): -> FADING IN, link to adder, unblock (short fade)
110 * - stopped for another stream: -> PENDING_REMOVE
111 * - rb_player_set_time(): -> perform seek
112 *
113 * from FADING_OUT:
114 *
115 * - fade out finishes: -> PENDING_REMOVE
116 * - EOS: -> PENDING_REMOVE
117 * - reused for another stream: -> REUSING; block, unlink
118 *
119 * from FADING_OUT_PAUSED:
120 *
121 * - fade out finishes: -> SEEKING_PAUSED, block, unlink
122 * - EOS: -> PENDING_REMOVE
123 * - reused for another stream: -> REUSING, block, unlink
124 * - rb_player_set_time(): -> SEEKING_PAUSED, block, unlink
125 *
126 * from PENDING_REMOVE:
127 * - rb_player_set_time(): -> block, seek, -> SEEKING_EOS
128 * - reap_streams idle handler called: -> unlink from adder, stream destroyed
129 *
130 * from SEEKING_EOS:
131 * - block completes -> link, unblock, -> PLAYING
132 * - rb_player_pause() -> SEEKING_PAUSED
133 *
134 * from REUSING:
135 * - EOS: emit reuse-stream, -> PLAYING
136 * - rb_player_play(): -> block, unlink
137 * - blocked: emit reuse-stream, link -> PLAYING
138 */
139
140 #include "config.h"
141 #include <math.h>
142
143 #include <glib/gi18n.h>
144 #include <gst/gst.h>
145 #include <gst/controller/gstcontroller.h>
146 #include <gst/base/gstbasetransform.h>
147 #include <gst/interfaces/streamvolume.h>
148 #include <gst/pbutils/pbutils.h>
149
150 #include "rb-player.h"
151 #include "rb-player-gst-xfade.h"
152 #include "rb-debug.h"
153 #include "rb-file-helpers.h"
154 #include "rb-util.h"
155 #include "rb-marshal.h"
156 #include "rb-player-gst-tee.h"
157 #include "rb-player-gst-filter.h"
158 #include "rb-player-gst-helper.h"
159
160 static void rb_player_init (RBPlayerIface *iface);
161 static void rb_player_gst_tee_init (RBPlayerGstTeeIface *iface);
162 static void rb_player_gst_filter_init (RBPlayerGstFilterIface *iface);
163 static void rb_player_gst_xfade_dispose (GObject *object);
164 static void rb_player_gst_xfade_finalize (GObject *object);
165
166 static gboolean rb_player_gst_xfade_open (RBPlayer *player,
167 const char *uri,
168 gpointer stream_data,
169 GDestroyNotify stream_data_destroy,
170 GError **error);
171 static gboolean rb_player_gst_xfade_opened (RBPlayer *player);
172 static gboolean rb_player_gst_xfade_close (RBPlayer *player, const char *uri, GError **error);
173 static gboolean rb_player_gst_xfade_play (RBPlayer *player, RBPlayerPlayType play_type, gint64 crossfade, GError **error);
174 static void rb_player_gst_xfade_pause (RBPlayer *player);
175 static gboolean rb_player_gst_xfade_playing (RBPlayer *player);
176 static gboolean rb_player_gst_xfade_seekable (RBPlayer *player);
177 static void rb_player_gst_xfade_set_time (RBPlayer *player, gint64 time);
178 static gint64 rb_player_gst_xfade_get_time (RBPlayer *player);
179 static void rb_player_gst_xfade_set_volume (RBPlayer *player, float volume);
180 static float rb_player_gst_xfade_get_volume (RBPlayer *player);
181 static gboolean rb_player_gst_xfade_add_tee (RBPlayerGstTee *player, GstElement *element);
182 static gboolean rb_player_gst_xfade_add_filter (RBPlayerGstFilter *player, GstElement *element);
183 static gboolean rb_player_gst_xfade_remove_tee (RBPlayerGstTee *player, GstElement *element);
184 static gboolean rb_player_gst_xfade_remove_filter (RBPlayerGstFilter *player, GstElement *element);
185
186 static gboolean create_sink (RBPlayerGstXFade *player, GError **error);
187 static gboolean start_sink (RBPlayerGstXFade *player, GError **error);
188 static gboolean stop_sink (RBPlayerGstXFade *player);
189 static void maybe_stop_sink (RBPlayerGstXFade *player);
190
191 GType rb_xfade_stream_get_type (void);
192 GType rb_xfade_stream_bin_get_type (void);
193
194 G_DEFINE_TYPE_WITH_CODE(RBPlayerGstXFade, rb_player_gst_xfade, G_TYPE_OBJECT,
195 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER,
196 rb_player_init)
197 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_TEE,
198 rb_player_gst_tee_init)
199 G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_FILTER,
200 rb_player_gst_filter_init))
201
202 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYER_GST_XFADE, RBPlayerGstXFadePrivate))
203
204 #define RB_PLAYER_GST_XFADE_TICK_HZ 5
205
206 #define EPSILON (0.001)
207 #define STREAM_PLAYING_MESSAGE "rb-stream-playing"
208 #define FADE_OUT_DONE_MESSAGE "rb-fade-out-done"
209 #define FADE_IN_DONE_MESSAGE "rb-fade-in-done"
210 #define STREAM_EOS_MESSAGE "rb-stream-eos"
211
212 #define PAUSE_FADE_LENGTH (GST_SECOND / 2)
213
214 enum
215 {
216 PROP_0,
217 PROP_BUS
218 };
219
220 enum
221 {
222 PREPARE_SOURCE,
223 CAN_REUSE_STREAM,
224 REUSE_STREAM,
225 MISSING_PLUGINS,
226 GET_STREAM_FILTERS,
227 LAST_SIGNAL
228 };
229
230 /* copied from gsturidecodebin.c:stream_uris */
231 static const char *stream_schemes[] = {
232 "http", "https", "mms", "mmsh", "mmsu", "mmst", "ssh", "ftp", "sftp"
233 };
234
235 static guint signals[LAST_SIGNAL] = { 0 };
236
237 struct _RBPlayerGstXFadePrivate
238 {
239 /* probably don't need to store pointers to these either */
240 GstElement *pipeline;
241 GstElement *outputbin;
242 GstElement *silencebin;
243 GstElement *adder;
244 GstElement *capsfilter;
245 GstElement *volume;
246 GstElement *sink;
247 GstElement *tee;
248 GstElement *filterbin;
249 GstElement *filteridentity;
250 GstElement *filterconvert;
251 GstElement *volume_handler;
252 enum {
253 SINK_NULL,
254 SINK_STOPPED,
255 SINK_PLAYING
256 } sink_state;
257 GRecMutex sink_lock;
258
259 GList *waiting_tees;
260 GList *waiting_filters;
261
262 GRecMutex stream_list_lock;
263 GList *streams;
264 gint linked_streams;
265
266 int volume_changed;
267 int volume_applied;
268 float cur_volume;
269
270 guint tick_timeout_id;
271
272 guint stream_reap_id;
273 guint stop_sink_id;
274 guint bus_watch_id;
275 };
276
277
278 /* these aren't actually used to construct bitmasks,
279 * but we search the list that way.
280 */
281 typedef enum
282 {
283 /* stable states */
284 WAITING = 1,
285 PLAYING = 2,
286 PAUSED = 4,
287
288 /* transition states */
289 REUSING = 8,
290 PREROLLING = 16,
291 PREROLL_PLAY = 32,
292 FADING_IN = 64,
293 SEEKING = 128,
294 SEEKING_PAUSED = 256,
295 SEEKING_EOS = 512,
296 WAITING_EOS = 1024,
297 FADING_OUT = 2048,
298 FADING_OUT_PAUSED = 4096,
299 PENDING_REMOVE = 8192
300 } StreamState;
301
302 typedef struct {
303 GstBinClass bin_class;
304 } RBXFadeStreamClass;
305
306
307 typedef struct
308 {
309 GstBin parent;
310 RBPlayerGstXFade *player;
311
312 GMutex lock;
313
314 char *uri;
315 gpointer stream_data;
316 GDestroyNotify stream_data_destroy;
317
318 /* stream reuse data */
319 char *new_uri;
320 gpointer new_stream_data;
321 GDestroyNotify new_stream_data_destroy;
322
323 /* probably don't need to store pointers to all of these.. */
324 GstElement *decoder;
325 GstElement *volume;
326 GstElement *audioconvert;
327 GstElement *audioresample;
328 GstElement *capsfilter;
329 GstElement *preroll;
330 GstElement *identity;
331 gboolean decoder_linked;
332 gboolean emitted_playing;
333 gboolean emitted_fake_playing;
334
335 GstPad *decoder_pad;
336 GstPad *src_pad;
337 GstPad *ghost_pad;
338 GstPad *adder_pad;
339 gboolean src_blocked;
340 gboolean needs_unlink;
341 GstClockTime base_time;
342
343 gint64 seek_target;
344
345 GstInterpolationControlSource *fader;
346 StreamState state;
347 RBPlayerPlayType play_type;
348 gint64 crossfade;
349 gboolean fading;
350 gboolean starting_eos;
351 gboolean use_buffering;
352
353 gulong adjust_probe_id;
354
355 double fade_end;
356
357 gboolean emitted_error;
358 gulong error_idle_id;
359 GError *error;
360
361 GSList *missing_plugins;
362 gulong emit_missing_plugins_id;
363
364 GList *tags;
365 } RBXFadeStream;
366
367 #define RB_TYPE_XFADE_STREAM (rb_xfade_stream_get_type ())
368 #define RB_XFADE_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_XFADE_STREAM, RBXFadeStream))
369 #define RB_IS_XFADE_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_XFADE_STREAM))
370
371 static void adjust_stream_base_time (RBXFadeStream *stream);
372 static gboolean actually_start_stream (RBXFadeStream *stream, GError **error);
373
374 static void rb_xfade_stream_class_init (RBXFadeStreamClass *klass);
375
376 G_DEFINE_TYPE(RBXFadeStream, rb_xfade_stream, GST_TYPE_BIN)
377
378 static gboolean
379 rb_xfade_stream_send_event (GstElement *element, GstEvent *event)
380 {
381 GstPad *pad;
382 GstPad *ghost_pad;
383 gboolean ret;
384
385 /* just send the event to the element that provides the src pad */
386 ghost_pad = gst_element_get_pad (element, "src");
387 pad = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost_pad));
388
389 ret = gst_element_send_event (GST_PAD_PARENT (pad), event);
390
391 gst_object_unref (pad);
392 gst_object_unref (ghost_pad);
393
394 return ret;
395 }
396
397 static void
398 rb_xfade_stream_init (RBXFadeStream *stream)
399 {
400 g_mutex_init (&stream->lock);
401 }
402
403 static void
404 rb_xfade_stream_dispose_stream_data (RBXFadeStream *stream)
405 {
406 if (stream->stream_data && stream->stream_data_destroy) {
407 stream->stream_data_destroy (stream->stream_data);
408 }
409 stream->stream_data = NULL;
410 stream->stream_data_destroy = NULL;
411 }
412
413 static void
414 rb_xfade_stream_dispose (GObject *object)
415 {
416 RBXFadeStream *sd = RB_XFADE_STREAM (object);
417
418 rb_debug ("disposing stream %s", sd->uri);
419
420 if (sd->decoder != NULL) {
421 gst_object_unref (sd->decoder);
422 sd->decoder = NULL;
423 }
424
425 if (sd->volume != NULL) {
426 gst_object_unref (sd->volume);
427 sd->volume = NULL;
428 }
429
430 if (sd->fader != NULL) {
431 gst_object_unref (sd->fader);
432 sd->fader = NULL;
433 }
434
435 if (sd->audioconvert != NULL) {
436 gst_object_unref (sd->audioconvert);
437 sd->audioconvert = NULL;
438 }
439
440 if (sd->audioresample != NULL) {
441 gst_object_unref (sd->audioresample);
442 sd->audioresample = NULL;
443 }
444
445 if (sd->player != NULL) {
446 g_object_unref (sd->player);
447 sd->player = NULL;
448 }
449
450 if (sd->tags != NULL) {
451 rb_list_destroy_free (sd->tags, (GDestroyNotify) gst_tag_list_free);
452 sd->tags = NULL;
453 }
454
455 rb_xfade_stream_dispose_stream_data (sd);
456
457 G_OBJECT_CLASS (rb_xfade_stream_parent_class)->dispose (object);
458 }
459
460 static void
461 rb_xfade_stream_finalize (GObject *object)
462 {
463 RBXFadeStream *sd = RB_XFADE_STREAM (object);
464
465 g_free (sd->uri);
466
467 if (sd->error != NULL) {
468 g_error_free (sd->error);
469 }
470
471 G_OBJECT_CLASS (rb_xfade_stream_parent_class)->finalize (object);
472 }
473
474 static void
475 rb_xfade_stream_class_init (RBXFadeStreamClass *klass)
476 {
477 GObjectClass *object_class = G_OBJECT_CLASS (klass);
478 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
479
480 object_class->dispose = rb_xfade_stream_dispose;
481 object_class->finalize = rb_xfade_stream_finalize;
482
483 element_class->send_event = rb_xfade_stream_send_event;
484 }
485
486 /* caller must hold stream list lock */
487 static void
488 dump_stream_list (RBPlayerGstXFade *player)
489 {
490 GList *l;
491 if (player->priv->streams == NULL) {
492 rb_debug ("stream list is empty");
493 } else {
494 rb_debug ("current stream list:");
495 for (l = player->priv->streams; l != NULL; l = l->next) {
496 RBXFadeStream *stream = (RBXFadeStream *)l->data;
497 const char *statename = "<wtf>";
498 switch (stream->state) {
499 case WAITING: statename = "waiting"; break;
500 case PLAYING: statename = "playing"; break;
501 case PAUSED: statename = "paused"; break;
502
503 case REUSING: statename = "reusing"; break;
504 case PREROLLING: statename = "prerolling"; break;
505 case PREROLL_PLAY: statename = "preroll->play"; break;
506 case FADING_IN: statename = "fading in"; break;
507 case SEEKING: statename = "seeking"; break;
508 case SEEKING_PAUSED: statename = "seeking->paused"; break;
509 case SEEKING_EOS: statename = "seeking post EOS"; break;
510 case WAITING_EOS: statename = "waiting for EOS"; break;
511 case FADING_OUT: statename = "fading out"; break;
512 case FADING_OUT_PAUSED: statename = "fading->paused"; break;
513
514 case PENDING_REMOVE: statename = "pending remove"; break;
515 }
516
517 rb_debug ("[%s] %s", statename, stream->uri);
518 }
519 }
520 }
521
522 /* caller must hold stream list lock */
523 static RBXFadeStream *
524 find_stream_by_uri (RBPlayerGstXFade *player, const char *uri)
525 {
526 GList *i;
527 if (uri == NULL)
528 return NULL;
529
530 for (i = player->priv->streams; i != NULL; i = i->next) {
531 RBXFadeStream *stream = (RBXFadeStream *)i->data;
532 if (strcmp (uri, stream->uri) == 0)
533 return g_object_ref (stream);
534 }
535 return NULL;
536 }
537
538 /* caller must hold stream list lock */
539 static RBXFadeStream *
540 find_stream_by_element (RBPlayerGstXFade *player, GstElement *element)
541 {
542 GList *i;
543
544 for (i = player->priv->streams; i != NULL; i = i->next) {
545 RBXFadeStream *stream;
546 GstElement *e;
547
548 stream = (RBXFadeStream *)i->data;
549 e = element;
550 while (e != NULL) {
551 if (e == GST_ELEMENT (stream))
552 return g_object_ref (stream);
553
554 e = GST_ELEMENT_PARENT (e);
555 }
556 }
557
558 return NULL;
559 }
560
561 /* caller must hold stream list lock */
562 static RBXFadeStream *
563 find_stream_by_state (RBPlayerGstXFade *player, gint state_mask)
564 {
565 GList *i;
566
567 for (i = player->priv->streams; i != NULL; i = i->next) {
568 RBXFadeStream *stream;
569
570 stream = (RBXFadeStream *)i->data;
571 if ((stream->state & state_mask) != 0) {
572 return g_object_ref (stream);
573 }
574 }
575
576 return NULL;
577 }
578
579 static void
580 rb_player_gst_xfade_get_property (GObject *object,
581 guint prop_id,
582 GValue *value,
583 GParamSpec *pspec)
584 {
585 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);
586
587 switch (prop_id) {
588 case PROP_BUS:
589 if (player->priv->pipeline) {
590 GstBus *bus;
591 bus = gst_element_get_bus (player->priv->pipeline);
592 g_value_set_object (value, bus);
593 gst_object_unref (bus);
594 }
595 break;
596 default:
597 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
598 break;
599 }
600 }
601
602 static void
603 rb_player_gst_xfade_set_property (GObject *object,
604 guint prop_id,
605 const GValue *value,
606 GParamSpec *pspec)
607 {
608 /*RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);*/
609
610 switch (prop_id) {
611 default:
612 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
613 break;
614 }
615 }
616
617 static void
618 rb_player_gst_xfade_class_init (RBPlayerGstXFadeClass *klass)
619 {
620 GObjectClass *object_class = G_OBJECT_CLASS (klass);
621
622 object_class->dispose = rb_player_gst_xfade_dispose;
623 object_class->finalize = rb_player_gst_xfade_finalize;
624 object_class->set_property = rb_player_gst_xfade_set_property;
625 object_class->get_property = rb_player_gst_xfade_get_property;
626
627 g_object_class_install_property (object_class,
628 PROP_BUS,
629 g_param_spec_object ("bus",
630 "bus",
631 "GStreamer message bus",
632 GST_TYPE_BUS,
633 G_PARAM_READABLE));
634
635 signals[PREPARE_SOURCE] =
636 g_signal_new ("prepare-source",
637 G_OBJECT_CLASS_TYPE (object_class),
638 G_SIGNAL_RUN_LAST,
639 G_STRUCT_OFFSET (RBPlayerGstXFadeClass, prepare_source),
640 NULL, NULL,
641 rb_marshal_VOID__STRING_OBJECT,
642 G_TYPE_NONE,
643 2,
644 G_TYPE_STRING, GST_TYPE_ELEMENT);
645 signals[CAN_REUSE_STREAM] =
646 g_signal_new ("can-reuse-stream",
647 G_OBJECT_CLASS_TYPE (object_class),
648 G_SIGNAL_RUN_LAST,
649 G_STRUCT_OFFSET (RBPlayerGstXFadeClass, can_reuse_stream),
650 NULL, NULL,
651 rb_marshal_BOOLEAN__STRING_STRING_OBJECT,
652 G_TYPE_BOOLEAN,
653 3,
654 G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
655 signals[REUSE_STREAM] =
656 g_signal_new ("reuse-stream",
657 G_OBJECT_CLASS_TYPE (object_class),
658 G_SIGNAL_RUN_LAST,
659 G_STRUCT_OFFSET (RBPlayerGstXFadeClass, reuse_stream),
660 NULL, NULL,
661 rb_marshal_VOID__STRING_STRING_OBJECT,
662 G_TYPE_NONE,
663 3,
664 G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
665 signals[MISSING_PLUGINS] =
666 g_signal_new ("missing-plugins",
667 G_OBJECT_CLASS_TYPE (object_class),
668 G_SIGNAL_RUN_LAST,
669 0, /* no point handling this internally */
670 NULL, NULL,
671 rb_marshal_VOID__POINTER_POINTER_POINTER,
672 G_TYPE_NONE,
673 3,
674 G_TYPE_POINTER, G_TYPE_STRV, G_TYPE_STRV);
675 signals[GET_STREAM_FILTERS] =
676 g_signal_new ("get-stream-filters",
677 G_OBJECT_CLASS_TYPE (object_class),
678 G_SIGNAL_RUN_LAST,
679 0,
680 rb_signal_accumulator_value_array, NULL,
681 rb_marshal_BOXED__STRING,
682 G_TYPE_ARRAY,
683 1,
684 G_TYPE_STRING);
685
686 g_type_class_add_private (klass, sizeof (RBPlayerGstXFadePrivate));
687 }
688
689 static void
690 rb_player_init (RBPlayerIface *iface)
691 {
692 iface->open = rb_player_gst_xfade_open;
693 iface->opened = rb_player_gst_xfade_opened;
694 iface->close = rb_player_gst_xfade_close;
695 iface->play = rb_player_gst_xfade_play;
696 iface->pause = rb_player_gst_xfade_pause;
697 iface->playing = rb_player_gst_xfade_playing;
698 iface->set_volume = rb_player_gst_xfade_set_volume;
699 iface->get_volume = rb_player_gst_xfade_get_volume;
700 iface->seekable = rb_player_gst_xfade_seekable;
701 iface->set_time = rb_player_gst_xfade_set_time;
702 iface->get_time = rb_player_gst_xfade_get_time;
703 iface->multiple_open = (RBPlayerFeatureFunc) rb_true_function;
704 }
705
706 static void
707 rb_player_gst_tee_init (RBPlayerGstTeeIface *iface)
708 {
709 iface->add_tee = rb_player_gst_xfade_add_tee;
710 iface->remove_tee = rb_player_gst_xfade_remove_tee;
711 }
712
713 static void
714 rb_player_gst_filter_init (RBPlayerGstFilterIface *iface)
715 {
716 iface->add_filter = rb_player_gst_xfade_add_filter;
717 iface->remove_filter = rb_player_gst_xfade_remove_filter;
718 }
719
720
721 static void
722 rb_player_gst_xfade_init (RBPlayerGstXFade *player)
723 {
724 player->priv = GET_PRIVATE (player);
725
726 g_rec_mutex_init (&player->priv->stream_list_lock);
727 g_rec_mutex_init (&player->priv->sink_lock);
728 player->priv->cur_volume = 1.0f;
729 }
730
731 static void
732 rb_player_gst_xfade_dispose (GObject *object)
733 {
734 RBPlayerGstXFade *player;
735 GList *l;
736
737 g_return_if_fail (RB_IS_PLAYER_GST_XFADE (object));
738 player = RB_PLAYER_GST_XFADE (object);
739
740 /* clean up streams */
741 g_rec_mutex_lock (&player->priv->stream_list_lock);
742 for (l = player->priv->streams; l != NULL; l = l->next) {
743 RBXFadeStream *stream = (RBXFadeStream *)l->data;
744
745 /* unlink instead? */
746 gst_element_set_state (GST_ELEMENT (stream), GST_STATE_NULL);
747
748 g_object_unref (stream);
749 }
750 g_list_free (player->priv->streams);
751 player->priv->streams = NULL;
752 g_rec_mutex_unlock (&player->priv->stream_list_lock);
753
754 if (player->priv->volume_handler) {
755 g_object_unref (player->priv->volume_handler);
756 player->priv->volume_handler = NULL;
757 }
758
759 g_rec_mutex_lock (&player->priv->sink_lock);
760 stop_sink (player);
761 g_rec_mutex_unlock (&player->priv->sink_lock);
762
763 if (player->priv->pipeline != NULL) {
764 /* maybe we should keep references to the adder, sink, etc.? */
765 gst_element_set_state (player->priv->pipeline, GST_STATE_NULL);
766 g_object_unref (player->priv->pipeline);
767 player->priv->pipeline = NULL;
768 }
769
770 G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->dispose (object);
771 }
772
773 static void
774 rb_player_gst_xfade_finalize (GObject *object)
775 {
776 RBPlayerGstXFade *player;
777
778 player = RB_PLAYER_GST_XFADE (object);
779
780 if (player->priv->waiting_tees) {
781 g_list_foreach (player->priv->waiting_tees, (GFunc)gst_object_sink, NULL);
782 }
783 g_list_free (player->priv->waiting_tees);
784
785 if (player->priv->waiting_filters) {
786 g_list_foreach (player->priv->waiting_filters, (GFunc)gst_object_sink, NULL);
787 }
788 g_list_free (player->priv->waiting_filters);
789
790 G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->finalize (object);
791 }
792
793 RBPlayer *
794 rb_player_gst_xfade_new (GError **error)
795 {
796 RBPlayer *mp;
797
798 mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER_GST_XFADE, NULL, NULL));
799
800 return mp;
801 }
802
803 static gboolean
804 emit_stream_error_cb (RBXFadeStream *stream)
805 {
806 stream->error_idle_id = 0;
807 _rb_player_emit_error (RB_PLAYER (stream->player),
808 stream->stream_data,
809 stream->error);
810 g_error_free (stream->error);
811 stream->error = NULL;
812
813 return FALSE;
814 }
815
816 static void
817 emit_stream_error (RBXFadeStream *stream, GError *error)
818 {
819 if (stream->error_idle_id != 0) {
820 g_error_free (error);
821 } else {
822 stream->error = error;
823 stream->error_idle_id = g_idle_add ((GSourceFunc) emit_stream_error_cb,
824 stream);
825 }
826 }
827
828 static void
829 post_stream_playing_message (RBXFadeStream *stream, gboolean fake)
830 {
831 GstMessage *msg;
832 GstStructure *s;
833
834 if (stream->emitted_playing) {
835 return;
836 }
837
838 rb_debug ("posting " STREAM_PLAYING_MESSAGE " message for stream %s", stream->uri);
839 s = gst_structure_new (STREAM_PLAYING_MESSAGE, NULL);
840 msg = gst_message_new_application (GST_OBJECT (stream), s);
841 gst_element_post_message (GST_ELEMENT (stream), msg);
842
843 if (fake == FALSE) {
844 stream->emitted_playing = TRUE;
845 } else {
846 stream->emitted_fake_playing = TRUE;
847 }
848 }
849
850 static gboolean
851 adjust_base_time_probe_cb (GstPad *pad, GstBuffer *data, RBXFadeStream *stream)
852 {
853 rb_debug ("attempting to adjust base time for stream %s", stream->uri);
854 adjust_stream_base_time (stream);
855 return TRUE;
856 }
857
858 /* updates a stream's base time so its position is reported correctly */
859 static void
860 adjust_stream_base_time (RBXFadeStream *stream)
861 {
862 GstFormat format;
863 gint64 output_pos = -1;
864 gint64 stream_pos = -1;
865
866 g_mutex_lock (&stream->lock);
867
868 if (stream->adder_pad == NULL) {
869 rb_debug ("stream isn't linked, can't adjust base time");
870 g_mutex_unlock (&stream->lock);
871 return;
872 }
873
874 format = GST_FORMAT_TIME;
875 gst_element_query_position (GST_PAD_PARENT (stream->adder_pad), &format, &output_pos);
876 if (output_pos != -1) {
877 stream->base_time = output_pos;
878 }
879
880 /* offset the base position to account for the current stream position */
881 format = GST_FORMAT_TIME;
882 gst_element_query_position (stream->volume, &format, &stream_pos);
883 if (stream_pos != -1) {
884 rb_debug ("adjusting base time: %" G_GINT64_FORMAT
885 " - %" G_GINT64_FORMAT " => %" G_GINT64_FORMAT,
886 stream->base_time, stream_pos,
887 stream->base_time - stream_pos);
888 stream->base_time -= stream_pos;
889
890 /* once we've successfully adjusted the base time, we don't need the data probe */
891 if (stream->adjust_probe_id != 0) {
892 gst_pad_remove_buffer_probe (stream->ghost_pad,
893 stream->adjust_probe_id);
894 stream->adjust_probe_id = 0;
895 }
896 } else {
897 rb_debug ("unable to adjust base time as position query failed");
898
899 /* add a pad probe to attempt to adjust when the next buffer goes out */
900 if (stream->adjust_probe_id == 0) {
901 stream->adjust_probe_id =
902 gst_pad_add_buffer_probe (stream->ghost_pad,
903 G_CALLBACK (adjust_base_time_probe_cb),
904 stream);
905 }
906 }
907
908 g_mutex_unlock (&stream->lock);
909 }
910
911 /* called on a streaming thread when the volume level for a stream changes. */
912 static void
913 volume_changed_cb (GObject *object, GParamSpec *pspec, RBPlayerGstXFade *player)
914 {
915 RBXFadeStream *stream;
916 gdouble vol;
917 char *message = NULL;
918
919 /* post app messages on the bus when fades complete.
920 * our bus callback will handle them on the main thread.
921 */
922
923 g_rec_mutex_lock (&player->priv->stream_list_lock);
924 stream = find_stream_by_element (player, GST_ELEMENT (object));
925 g_rec_mutex_unlock (&player->priv->stream_list_lock);
926
927 if (stream == NULL) {
928 rb_debug ("got volume change for unknown stream");
929 return;
930 }
931
932 g_mutex_lock (&stream->lock);
933
934 /* check if the fade is complete */
935 g_object_get (stream->volume, "volume", &vol, NULL);
936 switch (stream->state) {
937 case FADING_IN:
938 if (vol > (stream->fade_end - EPSILON) && stream->fading) {
939 rb_debug ("stream %s fully faded in (at %f) -> PLAYING state", stream->uri, vol);
940 /*message = FADE_IN_DONE_MESSAGE;*/ /* not actually used */
941 stream->fading = FALSE;
942 stream->state = PLAYING;
943
944 /*} else {
945 rb_debug ("fading %s in: %f", stream->uri, (float)vol);*/
946 }
947 break;
948 case FADING_OUT:
949 case FADING_OUT_PAUSED:
950 if (vol < (stream->fade_end + EPSILON)) {
951 rb_debug ("stream %s fully faded out (at %f)", stream->uri, vol);
952 if (stream->fading) {
953 message = FADE_OUT_DONE_MESSAGE;
954 stream->fading = FALSE;
955 }
956 } else {
957 /*rb_debug ("fading %s out: %f", stream->uri, (float)vol);*/
958 /* force the volume element out of passthrough mode so it
959 * continues to update the controller (otherwise, if the
960 * fade out starts at 1.0, it never gets anywhere)
961 */
962 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
963 }
964 break;
965 default:
966 /*rb_debug ("unexpectedly got a volume change for stream %s to %f (not fading)", stream->uri, (float)vol);*/
967 break;
968 }
969
970 g_mutex_unlock (&stream->lock);
971
972 if (message != NULL) {
973 GstMessage *msg;
974 GstStructure *s;
975
976 rb_debug ("posting %s message for stream %s", message, stream->uri);
977 s = gst_structure_new (message, NULL);
978 msg = gst_message_new_application (GST_OBJECT (object), s);
979 gst_element_post_message (GST_ELEMENT (object), msg);
980 }
981
982 g_object_unref (stream);
983 }
984
985 /* starts a volume slide on a stream.
986 * volume_changed_cb watches the volume change
987 * and posts a message on the bus when the slide
988 * is done.
989 */
990 static void
991 start_stream_fade (RBXFadeStream *stream, double start, double end, gint64 time)
992 {
993 GValue v = {0,};
994 gint64 pos = -1;
995 GstFormat format = GST_FORMAT_TIME;
996
997 /* hmm, can we take the stream lock safely here? probably should.. */
998
999 gst_element_query_position (stream->volume, &format, &pos);
1000 if (pos < 0) {
1001 /* probably means we haven't actually started the stream yet.
1002 * we also get (weird) negative results with some decoders
1003 * (mad but not flump3dec, for instance) immediately after prerolling.
1004 * the controller doesn't seem to work if we give it a 0 timestamp
1005 * here, but something unnoticeably later does work.
1006 */
1007 pos = 100000;
1008 }
1009 if (format != GST_FORMAT_TIME) {
1010 rb_debug ("got position query results in some other format: %s", gst_format_get_name (format));
1011 pos = 0;
1012 }
1013
1014 rb_debug ("fading stream %s: [%f, %" G_GINT64_FORMAT "] to [%f, %" G_GINT64_FORMAT "]",
1015 stream->uri,
1016 (float)start, pos,
1017 (float)end, pos + time);
1018
1019 g_signal_handlers_block_by_func (stream->volume, volume_changed_cb, stream->player);
1020
1021 /* apparently we need to set the starting volume, otherwise fading in doesn't work. */
1022 stream->fade_end = end;
1023 g_object_set (stream->volume, "volume", start, NULL);
1024
1025 gst_interpolation_control_source_unset_all (stream->fader);
1026
1027 g_value_init (&v, G_TYPE_DOUBLE);
1028 g_value_set_double (&v, start);
1029 if (gst_interpolation_control_source_set (stream->fader, pos, &v) == FALSE) {
1030 rb_debug ("controller didn't like our start point");
1031 }
1032 if (gst_interpolation_control_source_set (stream->fader, 0, &v) == FALSE) {
1033 rb_debug ("controller didn't like our 0 start point");
1034 }
1035 g_value_unset (&v);
1036
1037 g_value_init (&v, G_TYPE_DOUBLE);
1038 g_value_set_double (&v, end);
1039 if (gst_interpolation_control_source_set (stream->fader, pos + time, &v) == FALSE) {
1040 rb_debug ("controller didn't like our end point");
1041 }
1042 g_value_unset (&v);
1043
1044 g_signal_handlers_unblock_by_func (stream->volume, volume_changed_cb, stream->player);
1045
1046 stream->fading = TRUE;
1047
1048 /* tiny hack: if the controlled element is in passthrough mode, the
1049 * controller won't get updated.
1050 */
1051 gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
1052 }
1053
1054
1055 static void
1056 link_unblocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
1057 {
1058 GstStateChangeReturn state_ret;
1059 g_mutex_lock (&stream->lock);
1060
1061 /* sometimes we seem to get called twice */
1062 if (stream->state == FADING_IN || stream->state == PLAYING) {
1063 rb_debug ("stream %s already unblocked", stream->uri);
1064 g_mutex_unlock (&stream->lock);
1065 return;
1066 }
1067
1068 rb_debug ("stream %s is unblocked -> FADING_IN | PLAYING", stream->uri);
1069 stream->src_blocked = FALSE;
1070 if (stream->fading)
1071 stream->state = FADING_IN;
1072 else
1073 stream->state = PLAYING;
1074
1075 g_mutex_unlock (&stream->lock);
1076
1077 adjust_stream_base_time (stream);
1078
1079 /* should handle state change failures here.. */
1080 state_ret = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
1081 rb_debug ("stream %s state change returned: %s", stream->uri,
1082 gst_element_state_change_return_get_name (state_ret));
1083
1084 post_stream_playing_message (stream, FALSE);
1085 g_object_unref (stream);
1086 }
1087
1088 /* links a stream bin to the adder
1089 * - adds the bin to the pipeline
1090 * - links to a new adder pad
1091 * - unblocks the stream if it's blocked
1092 */
1093 static gboolean
1094 link_and_unblock_stream (RBXFadeStream *stream, GError **error)
1095 {
1096 GstPadLinkReturn plr;
1097 GstStateChangeReturn scr;
1098 RBPlayerGstXFade *player = stream->player;
1099
1100 if (start_sink (player, error) == FALSE) {
1101 rb_debug ("sink didn't start, so we're not going to link the stream");
1102 return FALSE;
1103 }
1104
1105 if (stream->adder_pad != NULL) {
1106 rb_debug ("stream %s is already linked", stream->uri);
1107 return TRUE;
1108 }
1109 stream->needs_unlink = FALSE;
1110
1111 rb_debug ("linking stream %s", stream->uri);
1112 if (GST_ELEMENT_PARENT (GST_ELEMENT (stream)) == NULL)
1113 gst_bin_add (GST_BIN (player->priv->pipeline), GST_ELEMENT (stream));
1114
1115 stream->adder_pad = gst_element_get_request_pad (player->priv->adder, "sink%d");
1116 if (stream->adder_pad == NULL) {
1117 /* this error message kind of sucks */
1118 rb_debug ("couldn't get adder pad to link in new stream");
1119 g_set_error (error,
1120 RB_PLAYER_ERROR,
1121 RB_PLAYER_ERROR_GENERAL,
1122 _("Failed to link new stream into GStreamer pipeline"));
1123 return FALSE;
1124 }
1125
1126 plr = gst_pad_link (stream->ghost_pad, stream->adder_pad);
1127 if (GST_PAD_LINK_FAILED (plr)) {
1128 gst_element_release_request_pad (player->priv->adder, stream->adder_pad);
1129 stream->adder_pad = NULL;
1130
1131 /* this error message kind of sucks */
1132 rb_debug ("linking stream pad to adder pad failed: %d", plr);
1133 g_set_error (error,
1134 RB_PLAYER_ERROR,
1135 RB_PLAYER_ERROR_GENERAL,
1136 _("Failed to link new stream into GStreamer pipeline"));
1137 return FALSE;
1138 }
1139
1140
1141 g_atomic_int_inc (&player->priv->linked_streams);
1142 rb_debug ("now have %d linked streams", player->priv->linked_streams);
1143
1144 if (stream->src_blocked) {
1145 g_object_ref (stream);
1146 gst_pad_set_blocked_async (stream->src_pad,
1147 FALSE,
1148 (GstPadBlockCallback) link_unblocked_cb,
1149 stream);
1150 return TRUE;
1151 } else {
1152 rb_debug ("??? stream %s is already unblocked -> PLAYING", stream->uri);
1153 stream->state = PLAYING;
1154 adjust_stream_base_time (stream);
1155
1156 scr = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
1157
1158 post_stream_playing_message (stream, FALSE);
1159
1160 if (scr == GST_STATE_CHANGE_FAILURE) {
1161 g_set_error (error,
1162 RB_PLAYER_ERROR,
1163 RB_PLAYER_ERROR_GENERAL,
1164 _("Failed to start new stream"));
1165 return FALSE;
1166 }
1167 return TRUE;
1168 }
1169 }
1170
1171 /*
1172 * reuses a stream. the stream reuse signal is handled by some
1173 * external code somewhere.
1174 */
1175 static void
1176 reuse_stream (RBXFadeStream *stream)
1177 {
1178 g_signal_emit (stream->player,
1179 signals[REUSE_STREAM], 0,
1180 stream->new_uri, stream->uri, GST_ELEMENT (stream));
1181
1182 /* replace URI and stream data */
1183 g_free (stream->uri);
1184 stream->uri = stream->new_uri;
1185
1186 rb_xfade_stream_dispose_stream_data (stream);
1187 stream->stream_data = stream->new_stream_data;
1188 stream->stream_data_destroy = stream->new_stream_data_destroy;
1189
1190 stream->new_uri = NULL;
1191 stream->new_stream_data = NULL;
1192 stream->new_stream_data_destroy = NULL;
1193
1194 stream->emitted_playing = FALSE;
1195 }
1196
1197
1198 /*
1199 * performs a seek on an unlinked and blocked stream.
1200 * if the stream is still in FADING_IN or PLAYING state,
1201 * relinks and unblocks the stream.
1202 */
1203 static void
1204 perform_seek (RBXFadeStream *stream)
1205 {
1206 GstEvent *event;
1207
1208 rb_debug ("sending seek event..");
1209 event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
1210 GST_SEEK_FLAG_FLUSH,
1211 GST_SEEK_TYPE_SET, stream->seek_target,
1212 GST_SEEK_TYPE_NONE, -1);
1213 gst_pad_send_event (stream->src_pad, event);
1214
1215 switch (stream->state) {
1216 case SEEKING:
1217 stream->state = PLAYING;
1218 break;
1219 case SEEKING_PAUSED:
1220 rb_debug ("leaving paused stream %s unlinked", stream->uri);
1221 stream->state = PAUSED;
1222 break;
1223 case SEEKING_EOS:
1224 rb_debug ("waiting for pad block to complete for %s before unlinking", stream->uri);
1225 break;
1226 default:
1227 break;
1228 }
1229 }
1230
1231 static gboolean
1232 perform_seek_idle (RBXFadeStream *stream)
1233 {
1234 perform_seek (stream);
1235 g_object_unref (stream);
1236 return FALSE;
1237 }
1238
1239 /*
1240 * called when a stream doing a post-EOS seek is blocked. this indicates
1241 * that the seek has completed (that's the only way data can flow out of
1242 * the stream bin), so the stream can be linked and unblocked.
1243 */
1244 static void
1245 post_eos_seek_blocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
1246 {
1247 GError *error = NULL;
1248
1249 g_mutex_lock (&stream->lock);
1250
1251 rb_debug ("stream %s is blocked; linking and unblocking", stream->uri);
1252 stream->src_blocked = TRUE;
1253 if (link_and_unblock_stream (stream, &error) == FALSE) {
1254 emit_stream_error (stream, error);
1255 }
1256
1257 g_mutex_unlock (&stream->lock);
1258 }
1259
1260 /*
1261 * called when a src pad for a stream is blocked during reuse.
1262 * we don't need to do anything here.
1263 */
1264 static void
1265 unlink_reuse_blocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
1266 {
1267 rb_debug ("stream %s pad blocked during reuse", stream->uri);
1268 }
1269
1270 static void
1271 unlink_reuse_relink (RBPlayerGstXFade *player, RBXFadeStream *stream)
1272 {
1273 GError *error = NULL;
1274
1275 g_mutex_lock (&stream->lock);
1276
1277 if (stream->adder_pad == NULL) {
1278 rb_debug ("stream %s doesn't need to be unlinked.. weird.", stream->uri);
1279 } else {
1280 rb_debug ("unlinking stream %s for reuse", stream->uri);
1281
1282 if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1283 g_warning ("Couldn't unlink stream %s: this is going to suck.", stream->uri);
1284 }
1285
1286 gst_element_release_request_pad (player->priv->adder, stream->adder_pad);
1287 stream->adder_pad = NULL;
1288
1289 (void) g_atomic_int_dec_and_test (&player->priv->linked_streams);
1290 rb_debug ("%d linked streams left", player->priv->linked_streams);
1291 }
1292
1293 stream->needs_unlink = FALSE;
1294 stream->emitted_playing = FALSE;
1295
1296 g_mutex_unlock (&stream->lock);
1297
1298 /* block the src pad so we don't get not-linked errors if it pushes a buffer
1299 * before we get around to relinking
1300 */
1301 gst_pad_set_blocked_async (stream->src_pad,
1302 TRUE,
1303 (GstPadBlockCallback) unlink_reuse_blocked_cb,
1304 stream);
1305 stream->src_blocked = TRUE;
1306
1307 reuse_stream (stream);
1308 if (link_and_unblock_stream (stream, &error) == FALSE) {
1309 emit_stream_error (stream, error);
1310 }
1311 }
1312
1313 /* called when a stream's source pad is blocked, so it can be unlinked
1314 * from the pipeline.
1315 */
1316 static void
1317 unlink_blocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
1318 {
1319 int stream_state;
1320 gboolean last;
1321 RBPlayerGstXFade *player;
1322 GError *error = NULL;
1323
1324 g_mutex_lock (&stream->lock);
1325
1326 if (stream->needs_unlink == FALSE || stream->adder_pad == NULL) {
1327 rb_debug ("stream %s doesn't need to be unlinked", stream->uri);
1328 g_mutex_unlock (&stream->lock);
1329 return;
1330 }
1331
1332 rb_debug ("stream %s is blocked; unlinking", stream->uri);
1333
1334 if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1335 g_warning ("Couldn't unlink stream %s: things will probably go quite badly from here on", stream->uri);
1336 }
1337 stream->needs_unlink = FALSE;
1338
1339 gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
1340 stream->adder_pad = NULL;
1341
1342 stream->src_blocked = TRUE;
1343 stream->emitted_playing = FALSE;
1344
1345 stream_state = stream->state;
1346 player = stream->player;
1347
1348 g_mutex_unlock (&stream->lock);
1349
1350 /* might want a stream-paused signal here? */
1351
1352 last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
1353 rb_debug ("%d linked streams left", player->priv->linked_streams);
1354
1355 /* handle unlinks for seeking and stream reuse */
1356 switch (stream_state) {
1357 case REUSING:
1358 reuse_stream (stream);
1359 if (link_and_unblock_stream (stream, &error) == FALSE) {
1360 emit_stream_error (stream, error);
1361 }
1362 break;
1363
1364 case SEEKING_PAUSED:
1365 g_idle_add ((GSourceFunc) perform_seek_idle, g_object_ref (stream));
1366 /* fall through. this only happens when pausing, so it's OK
1367 * to stop the sink here.
1368 */
1369 default:
1370 /* consider pausing the sink if this is the linked last stream */
1371 if (last) {
1372 maybe_stop_sink (player);
1373 }
1374
1375 break;
1376 }
1377 }
1378
1379 /*
1380 * blocks and unlinks a stream. this is the only way we can pause a stream -
1381 * if the stream is linked to the adder and the audio sink is in PLAYING, the
1382 * stream will play.
1383 */
1384 static void
1385 unlink_and_block_stream (RBXFadeStream *stream)
1386 {
1387 if (stream->adder_pad == NULL) {
1388 rb_debug ("stream %s is not linked", stream->uri);
1389 return;
1390 }
1391
1392 stream->needs_unlink = TRUE;
1393 if (stream->src_blocked) {
1394 /* probably shouldn't happen, but we'll handle it anyway */
1395 unlink_blocked_cb (stream->src_pad, TRUE, stream);
1396 } else {
1397 gst_pad_set_blocked_async (stream->src_pad,
1398 TRUE,
1399 (GstPadBlockCallback) unlink_blocked_cb,
1400 stream);
1401 }
1402 }
1403
1404 /*
1405 * sets a stream to NULL state, unlinks it from the adder,
1406 * removes it from the pipeline, removes it from the
1407 * stream list, and frees it (hopefully).
1408 *
1409 * must not be called on a streaming thread.
1410 */
1411 static void
1412 unlink_and_dispose_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
1413 {
1414 GstStateChangeReturn sr;
1415 gboolean was_linked = FALSE;
1416 gboolean was_in_pipeline = FALSE;
1417
1418 /* seems to be too much locking in here.. */
1419
1420
1421 rb_debug ("stopping stream %s", stream->uri);
1422 sr = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_NULL);
1423 if (sr == GST_STATE_CHANGE_ASYNC) {
1424 /* downward state transitions aren't supposed to return ASYNC.. */
1425 rb_debug ("!!! stream %s isn't cooperating", stream->uri);
1426 gst_element_get_state (GST_ELEMENT (stream), NULL, NULL, GST_CLOCK_TIME_NONE);
1427 }
1428
1429 g_mutex_lock (&stream->lock);
1430
1431 if (stream->adder_pad != NULL) {
1432 rb_debug ("unlinking stream %s", stream->uri);
1433 if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1434 g_warning ("Couldn't unlink stream %s: things will probably go quite badly from here on", stream->uri);
1435 }
1436
1437 gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
1438 stream->adder_pad = NULL;
1439
1440 was_linked = TRUE;
1441 }
1442
1443 was_in_pipeline = (GST_ELEMENT_PARENT (GST_ELEMENT (stream)) == player->priv->pipeline);
1444
1445 g_mutex_unlock (&stream->lock);
1446
1447 if (was_in_pipeline)
1448 gst_bin_remove (GST_BIN (player->priv->pipeline), GST_ELEMENT (stream));
1449
1450 if (was_linked) {
1451 gboolean last;
1452
1453 last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
1454 rb_debug ("now have %d linked streams", player->priv->linked_streams);
1455
1456 if (last) {
1457 maybe_stop_sink (player);
1458 }
1459 }
1460
1461 g_rec_mutex_lock (&player->priv->stream_list_lock);
1462 player->priv->streams = g_list_remove (player->priv->streams, stream);
1463 dump_stream_list (player);
1464 g_rec_mutex_unlock (&player->priv->stream_list_lock);
1465
1466 g_object_unref (stream);
1467 }
1468
1469 /* idle handler used to clean up finished streams */
1470 static gboolean
1471 reap_streams (RBPlayerGstXFade *player)
1472 {
1473 GList *t;
1474 GList *reap = NULL;
1475
1476 g_rec_mutex_lock (&player->priv->stream_list_lock);
1477 player->priv->stream_reap_id = 0;
1478 dump_stream_list (player);
1479 for (t = player->priv->streams; t != NULL; t = t->next) {
1480 RBXFadeStream *stream = (RBXFadeStream *)t->data;
1481
1482 if (stream->state == PENDING_REMOVE) {
1483 reap = g_list_prepend (reap, stream);
1484 }
1485 }
1486 g_rec_mutex_unlock (&player->priv->stream_list_lock);
1487
1488 for (t = reap; t != NULL; t = t->next) {
1489 RBXFadeStream *stream = (RBXFadeStream *)t->data;
1490 rb_debug ("reaping stream %s", stream->uri);
1491 unlink_and_dispose_stream (player, stream);
1492 }
1493 g_list_free (reap);
1494
1495 return FALSE;
1496 }
1497
1498 /* schedules a call to reap_streams */
1499 static void
1500 schedule_stream_reap (RBPlayerGstXFade *player)
1501 {
1502 g_rec_mutex_lock (&player->priv->stream_list_lock);
1503
1504 if (player->priv->stream_reap_id == 0) {
1505 dump_stream_list (player);
1506 player->priv->stream_reap_id = g_idle_add ((GSourceFunc) reap_streams, player);
1507 }
1508
1509 g_rec_mutex_unlock (&player->priv->stream_list_lock);
1510 }
1511
1512 /* emits a tag signal from the player, maybe */
1513 static void
1514 process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
1515 {
1516 RBMetaDataField field;
1517 GValue value = {0,};
1518
1519 /* process embedded images */
1520 if (!g_strcmp0 (tag, GST_TAG_IMAGE) || !g_strcmp0 (tag, GST_TAG_PREVIEW_IMAGE)) {
1521 GdkPixbuf *pixbuf;
1522 pixbuf = rb_gst_process_embedded_image (list, tag);
1523 if (pixbuf != NULL) {
1524 _rb_player_emit_image (RB_PLAYER (stream->player),
1525 stream->stream_data,
1526 pixbuf);
1527 g_object_unref (pixbuf);
1528 }
1529 } else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
1530 rb_debug ("emitting info field %d", field);
1531 _rb_player_emit_info (RB_PLAYER (stream->player),
1532 stream->stream_data,
1533 field,
1534 &value);
1535 g_value_unset (&value);
1536 }
1537 }
1538
1539
1540 static gboolean
1541 emit_missing_plugins (RBXFadeStream *stream)
1542 {
1543 char **details;
1544 char **descriptions;
1545 int count;
1546 GSList *t;
1547 int i;
1548
1549 stream->emit_missing_plugins_id = 0;
1550 count = g_slist_length (stream->missing_plugins);
1551
1552 details = g_new0 (char *, count + 1);
1553 descriptions = g_new0 (char *, count + 1);
1554 i = 0;
1555 for (t = stream->missing_plugins; t != NULL; t = t->next) {
1556 GstMessage *msg = GST_MESSAGE (t->data);
1557 char *detail;
1558 char *description;
1559
1560 detail = gst_missing_plugin_message_get_installer_detail (msg);
1561 description = gst_missing_plugin_message_get_description (msg);
1562 details[i] = g_strdup (detail);
1563 descriptions[i] = g_strdup (description);
1564 i++;
1565
1566 gst_message_unref (msg);
1567 }
1568
1569 g_signal_emit (stream->player, signals[MISSING_PLUGINS], 0, stream->stream_data, details, descriptions);
1570 g_strfreev (details);
1571 g_strfreev (descriptions);
1572
1573 g_slist_free (stream->missing_plugins);
1574 stream->missing_plugins = NULL;
1575
1576 return FALSE;
1577 }
1578
1579
1580 static void
1581 rb_player_gst_xfade_handle_missing_plugin_message (RBPlayerGstXFade *player, RBXFadeStream *stream, GstMessage *message)
1582 {
1583 if (stream == NULL) {
1584 rb_debug ("got missing-plugin message from unknown stream");
1585 return;
1586 }
1587
1588 rb_debug ("got missing-plugin message from %s: %s",
1589 stream->uri,
1590 gst_missing_plugin_message_get_installer_detail (message));
1591
1592 /* can only handle missing-plugins while prerolling */
1593 switch (stream->state) {
1594 case PREROLLING:
1595 case PREROLL_PLAY:
1596 stream->missing_plugins = g_slist_prepend (stream->missing_plugins,
1597 gst_message_ref (message));
1598 if (stream->emit_missing_plugins_id == 0) {
1599 stream->emit_missing_plugins_id =
1600 g_idle_add ((GSourceFunc) emit_missing_plugins,
1601 g_object_ref (stream));
1602 }
1603
1604 /* what do we do now? if we're missing the decoder
1605 * or something, it'll never preroll..
1606 */
1607 break;
1608
1609 default:
1610 rb_debug ("can't process missing-plugin messages for this stream now");
1611 break;
1612 }
1613 }
1614
1615 static void
1616 start_waiting_eos_streams (RBPlayerGstXFade *player)
1617 {
1618 GList *l;
1619 GList *to_start = NULL;
1620
1621 g_rec_mutex_lock (&player->priv->stream_list_lock);
1622 for (l = player->priv->streams; l != NULL; l = l->next) {
1623 RBXFadeStream *pstream = l->data;
1624 if (pstream->state == WAITING_EOS && pstream->starting_eos == FALSE) {
1625 pstream->starting_eos = TRUE;
1626 to_start = g_list_prepend (to_start, g_object_ref (pstream));
1627 }
1628 }
1629 g_rec_mutex_unlock (&player->priv->stream_list_lock);
1630
1631 for (l = to_start; l != NULL; l = l->next) {
1632 RBXFadeStream *pstream = l->data;
1633 GError *error = NULL;
1634
1635 rb_debug ("starting stream %s on EOS from previous", pstream->uri);
1636 if (link_and_unblock_stream (pstream, &error) == FALSE) {
1637 emit_stream_error (pstream, error);
1638 }
1639
1640 g_object_unref (pstream);
1641 }
1642 g_list_free (to_start);
1643 }
1644
1645 /* gstreamer message bus callback */
1646 static gboolean
1647 rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *player)
1648 {
1649 RBXFadeStream *stream;
1650 GstObject *message_src;
1651
1652 g_return_val_if_fail (player != NULL, FALSE);
1653
1654 g_rec_mutex_lock (&player->priv->stream_list_lock);
1655
1656 message_src = GST_MESSAGE_SRC (message);
1657 if (GST_IS_PAD (message_src)) {
1658 message_src = GST_OBJECT_PARENT (message_src);
1659 }
1660 stream = find_stream_by_element (player, GST_ELEMENT (message_src));
1661 g_rec_mutex_unlock (&player->priv->stream_list_lock);
1662
1663 switch (GST_MESSAGE_TYPE (message)) {
1664 case GST_MESSAGE_ERROR:
1665 {
1666 char *debug;
1667 GError *error, *sig_error;
1668 int code;
1669 gboolean emit = TRUE;
1670
1671 gst_message_parse_error (message, &error, &debug);
1672
1673 if (stream == NULL) {
1674 rb_debug ("Couldn't find stream for error \"%s\": %s", error->message, debug);
1675 g_error_free (error);
1676 g_free (debug);
1677 break;
1678 }
1679
1680 /* If we've already got an error, ignore 'internal data flow error'
1681 * type messages, as they're too generic to be helpful.
1682 */
1683 if (stream->emitted_error &&
1684 error->domain == GST_STREAM_ERROR &&
1685 error->code == GST_STREAM_ERROR_FAILED) {
1686 rb_debug ("Ignoring generic error \"%s\"", error->message);
1687 emit = FALSE;
1688 }
1689
1690 code = rb_gst_error_get_error_code (error);
1691
1692 if (emit) {
1693 rb_debug ("emitting error %s for stream %s", error->message, stream->uri);
1694 sig_error = g_error_new_literal (RB_PLAYER_ERROR,
1695 code,
1696 error->message);
1697 stream->emitted_error = TRUE;
1698 if (stream->emitted_playing == FALSE) {
1699 _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
1700 }
1701 _rb_player_emit_error (RB_PLAYER (player), stream->stream_data, sig_error);
1702 }
1703
1704 g_error_free (error);
1705 g_free (debug);
1706 break;
1707 }
1708 case GST_MESSAGE_TAG:
1709 if (stream == NULL) {
1710 rb_debug ("got tag message for unknown stream");
1711 } else {
1712 GstTagList *tags;
1713 gst_message_parse_tag (message, &tags);
1714
1715 g_mutex_lock (&stream->lock);
1716 if (stream->emitted_playing) {
1717 gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
1718 gst_tag_list_free (tags);
1719 } else {
1720 stream->tags = g_list_append (stream->tags, tags);
1721 }
1722 g_mutex_unlock (&stream->lock);
1723 }
1724 break;
1725
1726 case GST_MESSAGE_DURATION:
1727 if (stream == NULL) {
1728 rb_debug ("got duration message for unknown stream");
1729 } else {
1730 gint64 duration;
1731 GstFormat format;
1732 gst_message_parse_duration (message, &format, &duration);
1733 rb_debug ("got duration %" G_GINT64_FORMAT
1734 " for stream %s", duration, stream->uri);
1735 }
1736 break;
1737
1738 case GST_MESSAGE_APPLICATION:
1739 {
1740 /* process fade messages and emit signals for
1741 * other stuff.
1742 */
1743 const GstStructure *structure;
1744 const char *name;
1745
1746 structure = gst_message_get_structure (message);
1747 name = gst_structure_get_name (structure);
1748 if (stream == NULL) {
1749 rb_debug ("got application message %s for unknown stream", name);
1750 } else if (strcmp (name, STREAM_PLAYING_MESSAGE) == 0) {
1751 GList *l;
1752 GList *t;
1753
1754 rb_debug ("got stream playing message for %s", stream->uri);
1755 _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
1756
1757 /* process any buffered tag lists we received while prerolling the stream */
1758 g_mutex_lock (&stream->lock);
1759 l = stream->tags;
1760 stream->tags = NULL;
1761 g_mutex_unlock (&stream->lock);
1762
1763 for (t = l; t != NULL; t = t->next) {
1764 GstTagList *tags;
1765
1766 tags = (GstTagList *)t->data;
1767 rb_debug ("processing buffered taglist");
1768 gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
1769 gst_tag_list_free (tags);
1770 }
1771 g_list_free (l);
1772
1773 } else if (strcmp (name, FADE_IN_DONE_MESSAGE) == 0) {
1774 /* do something? */
1775 } else if (strcmp (name, FADE_OUT_DONE_MESSAGE) == 0) {
1776 switch (stream->state) {
1777 case FADING_OUT:
1778 /* stop the stream and dispose of it */
1779 rb_debug ("got fade-out-done for stream %s -> PENDING_REMOVE", stream->uri);
1780 g_mutex_lock (&stream->lock);
1781 stream->state = PENDING_REMOVE;
1782 g_mutex_unlock (&stream->lock);
1783 schedule_stream_reap (player);
1784 break;
1785
1786 case FADING_OUT_PAUSED:
1787 {
1788 /* try to seek back a bit to account for the fade */
1789 GstFormat format = GST_FORMAT_TIME;
1790 gint64 pos = -1;
1791
1792 g_mutex_lock (&stream->lock);
1793 gst_element_query_position (stream->volume, &format, &pos);
1794 if (pos != -1) {
1795 stream->seek_target = pos > PAUSE_FADE_LENGTH ? pos - PAUSE_FADE_LENGTH : 0;
1796 stream->state = SEEKING_PAUSED;
1797 rb_debug ("got fade-out-done for stream %s -> SEEKING_PAUSED [%" G_GINT64_FORMAT "]",
1798 stream->uri, stream->seek_target);
1799 } else {
1800 stream->state = PAUSED;
1801 rb_debug ("got fade-out-done for stream %s -> PAUSED (position query failed)",
1802 stream->uri);
1803 }
1804 g_mutex_unlock (&stream->lock);
1805 }
1806 unlink_and_block_stream (stream);
1807 break;
1808
1809 default:
1810 g_assert_not_reached ();
1811 }
1812 } else if (strcmp (name, STREAM_EOS_MESSAGE) == 0) {
1813 /* emit EOS (if we aren't already reusing the stream), then unlink it.
1814 * the stream stay around so we can seek back in it.
1815 */
1816 stream->needs_unlink = TRUE;
1817 if (stream->state != REUSING) {
1818 rb_debug ("got EOS message for stream %s -> PENDING_REMOVE", stream->uri);
1819 _rb_player_emit_eos (RB_PLAYER (player), stream->stream_data, FALSE);
1820 stream->state = PENDING_REMOVE;
1821
1822 unlink_blocked_cb (stream->src_pad, TRUE, stream);
1823
1824 /* start playing any streams that were waiting on an EOS
1825 * if they finished preroll between when we posted the EOS
1826 * message on the stream thread and now.
1827 */
1828 start_waiting_eos_streams (player);
1829 } else {
1830 /* no need to emit EOS here, we already know what to do next */
1831 rb_debug ("got EOS message for stream %s in REUSING state", stream->uri);
1832
1833 unlink_reuse_relink (player, stream);
1834 }
1835
1836 } else {
1837 _rb_player_emit_event (RB_PLAYER (player), stream->stream_data, name, NULL);
1838 }
1839
1840 break;
1841 }
1842 case GST_MESSAGE_BUFFERING:
1843 {
1844 const GstStructure *s;
1845 gint progress;
1846
1847 s = gst_message_get_structure (message);
1848 if (!gst_structure_get_int (s, "buffer-percent", &progress)) {
1849 g_warning ("Could not get value from BUFFERING message");
1850 break;
1851 }
1852 if (stream == NULL) {
1853 rb_debug ("got buffering message for unknown stream (%d)", progress);
1854 break;
1855 }
1856
1857 g_mutex_lock (&stream->lock);
1858 if (progress >= 100) {
1859 GError *error = NULL;
1860 switch (stream->state) {
1861 case PREROLLING:
1862 rb_debug ("stream %s is buffered, now waiting", stream->uri);
1863 stream->state = WAITING;
1864 break;
1865
1866 case WAITING_EOS:
1867 /* hmm, not sure */
1868 break;
1869
1870 case PREROLL_PLAY:
1871 rb_debug ("stream %s is buffered, now playing", stream->uri);
1872 if (actually_start_stream (stream, &error) == FALSE) {
1873 emit_stream_error (stream, error);
1874 }
1875 break;
1876
1877 default:
1878 rb_debug ("stream %s is buffered, resuming", stream->uri);
1879 link_and_unblock_stream (stream, &error);
1880 if (error) {
1881 g_warning ("couldn't restart newly buffered stream: %s", error->message);
1882 g_clear_error (&error);
1883 }
1884 break;
1885 }
1886 } else {
1887 switch (stream->state) {
1888 case PREROLLING:
1889 case WAITING:
1890 rb_debug ("still buffering, %d", progress);
1891 stream->state = PREROLLING;
1892 break;
1893
1894 case WAITING_EOS:
1895 /* not sure */
1896 break;
1897
1898 default:
1899 if (stream->adder_pad != NULL) {
1900 rb_debug ("stream buffering, stopping playback");
1901 unlink_and_block_stream (stream);
1902 }
1903 break;
1904 }
1905 }
1906 g_mutex_unlock (&stream->lock);
1907 _rb_player_emit_buffering (RB_PLAYER (player), stream->stream_data, progress);
1908 break;
1909 }
1910 case GST_MESSAGE_ELEMENT:
1911 {
1912 const GstStructure *s;
1913 const char *name;
1914
1915 if (gst_is_missing_plugin_message (message)) {
1916 rb_player_gst_xfade_handle_missing_plugin_message (player, stream, message);
1917 break;
1918 }
1919
1920 s = gst_message_get_structure (message);
1921 name = gst_structure_get_name (s);
1922 if ((strcmp (name, "imperfect-timestamp") == 0) ||
1923 (strcmp (name, "imperfect-offset") == 0)) {
1924 char *details;
1925 const char *uri = "unknown-stream";
1926
1927 if (stream != NULL) {
1928 uri = stream->uri;
1929 }
1930
1931 details = gst_structure_to_string (s);
1932 rb_debug_realf ("check-imperfect", __FILE__, __LINE__, TRUE, "%s: %s", uri, details);
1933 g_free (details);
1934 } else if (strcmp (name, "redirect") == 0) {
1935 const char *uri = gst_structure_get_string (s, "new-location");
1936 if (stream != NULL) {
1937 _rb_player_emit_redirect (RB_PLAYER (player), stream->stream_data, uri);
1938 } else {
1939 rb_debug ("got redirect to %s, but no active stream found", uri);
1940 }
1941 }
1942 break;
1943 }
1944 default:
1945 break;
1946 }
1947
1948 if (stream != NULL)
1949 g_object_unref (stream);
1950
1951 /* emit message signals too, so plugins can process bus messages */
1952 gst_bus_async_signal_func (bus, message, NULL);
1953
1954 return TRUE;
1955 }
1956
1957 static void
1958 stream_notify_source_cb (GstElement *decoder, GParamSpec *pspec, RBXFadeStream *stream)
1959 {
1960 GstElement *source;
1961 rb_debug ("got source notification for stream %s", stream->uri);
1962 g_object_get (decoder, "source", &source, NULL);
1963 g_signal_emit (stream->player, signals[PREPARE_SOURCE], 0, stream->uri, source);
1964 g_object_unref (source);
1965 }
1966
1967 /* links uridecodebin src pads to the rest of the output pipeline */
1968 static void
1969 stream_pad_added_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
1970 {
1971 GstCaps *caps;
1972 GstStructure *structure;
1973 const char *mediatype;
1974 GstPad *vpad;
1975
1976 /* make sure this is an audio pad */
1977 caps = gst_pad_get_caps (pad);
1978 if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
1979 rb_debug ("got empty/any decoded caps. hmm?");
1980 gst_caps_unref (caps);
1981 return;
1982 }
1983
1984 structure = gst_caps_get_structure (caps, 0);
1985 mediatype = gst_structure_get_name (structure);
1986 if (g_str_has_prefix (mediatype, "audio/x-raw") == FALSE) {
1987 rb_debug ("got non-audio decoded caps: %s", mediatype);
1988 } else if (stream->decoder_linked) {
1989 /* probably should never happen */
1990 rb_debug ("hmm, decoder is already linked");
1991 } else {
1992 rb_debug ("got decoded audio pad for stream %s", stream->uri);
1993 vpad = gst_element_get_static_pad (stream->identity, "sink");
1994 gst_pad_link (pad, vpad);
1995 gst_object_unref (vpad);
1996 stream->decoder_linked = TRUE;
1997
1998 stream->decoder_pad = gst_object_ref (pad);
1999 }
2000
2001 gst_caps_unref (caps);
2002 }
2003
2004 static void
2005 stream_pad_removed_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
2006 {
2007 if (pad == stream->decoder_pad) {
2008 rb_debug ("active output pad for stream %s removed", stream->uri);
2009 stream->decoder_linked = FALSE;
2010
2011 gst_object_unref (stream->decoder_pad);
2012 stream->decoder_pad = NULL;
2013 }
2014 }
2015
2016 /* handles EOS events on stream bins. since the pipeline as a whole
2017 * never goes EOS, we don't get an EOS bus message, so we have to handle
2018 * it here.
2019 *
2020 * when an EOS event is received, a bus message is posted, and any streams
2021 * in the WAITING_EOS state are started.
2022 *
2023 * when a new segment event is received, the stream base time is updated
2024 * (mostly for seeking)
2025 *
2026 * flush events are dropped, as they're only relevant inside the stream bin.
2027 * flushing the adder or the output bin mostly just breaks everything.
2028 */
2029 static gboolean
2030 stream_src_event_cb (GstPad *pad, GstEvent *event, RBXFadeStream *stream)
2031 {
2032 GstMessage *msg;
2033 GstStructure *s;
2034
2035 switch (GST_EVENT_TYPE (event)) {
2036 case GST_EVENT_EOS:
2037 rb_debug ("posting EOS message for stream %s", stream->uri);
2038 s = gst_structure_new (STREAM_EOS_MESSAGE, NULL);
2039 msg = gst_message_new_application (GST_OBJECT (stream), s);
2040 gst_element_post_message (GST_ELEMENT (stream), msg);
2041
2042 /* start playing any streams that were waiting on an EOS
2043 * (are we really allowed to do this on a stream thread?)
2044 */
2045 start_waiting_eos_streams (stream->player);
2046 break;
2047
2048 case GST_EVENT_NEWSEGMENT:
2049 rb_debug ("got new segment for stream %s", stream->uri);
2050 adjust_stream_base_time (stream);
2051 break;
2052
2053 case GST_EVENT_FLUSH_STOP:
2054 case GST_EVENT_FLUSH_START:
2055 rb_debug ("dropping %s event for stream %s", GST_EVENT_TYPE_NAME (event), stream->uri);
2056 return FALSE;
2057
2058 default:
2059 rb_debug ("got %s event for stream %s", GST_EVENT_TYPE_NAME (event), stream->uri);
2060 break;
2061 }
2062
2063 return TRUE;
2064 }
2065
2066 /*
2067 * stream playback bin:
2068 *
2069 * src [ ! queue ] ! decodebin2 ! audioconvert ! audioresample ! caps ! queue ! volume
2070 *
2071 * the first queue is only added for non-local streams. the thresholds
2072 * and such are probably going to be configurable at some point,
2073 * since people seem to get all whiny if they don't have a buffer
2074 * size slider to play with.
2075 *
2076 * the volume element is used for crossfading.
2077 */
2078 static RBXFadeStream *
2079 create_stream (RBPlayerGstXFade *player, const char *uri, gpointer stream_data, GDestroyNotify stream_data_destroy)
2080 {
2081 RBXFadeStream *stream;
2082 GstCaps *caps;
2083 GArray *stream_filters = NULL;
2084 GstElement *tail;
2085 GstController *controller;
2086 int i;
2087
2088 rb_debug ("creating new stream for %s (stream data %p)", uri, stream_data);
2089 stream = g_object_new (RB_TYPE_XFADE_STREAM, NULL, NULL);
2090 stream->player = g_object_ref (player);
2091 stream->stream_data = stream_data;
2092 stream->stream_data_destroy = stream_data_destroy;
2093 stream->uri = g_strdup (uri);
2094 stream->state = WAITING;
2095
2096 stream->use_buffering = FALSE;
2097 for (i = 0; i < G_N_ELEMENTS (stream_schemes); i++) {
2098 if (gst_uri_has_protocol (uri, stream_schemes[i])) {
2099 stream->use_buffering = TRUE;
2100 break;
2101 }
2102 }
2103
2104 /* kill the floating reference */
2105 g_object_ref (stream);
2106 gst_object_sink (stream);
2107 gst_element_set_locked_state (GST_ELEMENT (stream), TRUE);
2108 stream->decoder = gst_element_factory_make ("uridecodebin", NULL);
2109 if (stream->decoder == NULL) {
2110 rb_debug ("unable to create uridecodebin");
2111 g_object_unref (stream);
2112 return NULL;
2113 }
2114 gst_object_ref (stream->decoder);
2115 g_object_set (stream->decoder, "uri", uri, NULL);
2116
2117 /* connect uridecodebin to audioconvert when it creates its output pad */
2118 g_signal_connect_object (stream->decoder,
2119 "notify::source",
2120 G_CALLBACK (stream_notify_source_cb),
2121 stream,
2122 0);
2123 g_signal_connect_object (stream->decoder,
2124 "pad-added",
2125 G_CALLBACK (stream_pad_added_cb),
2126 stream,
2127 0);
2128 g_signal_connect_object (stream->decoder,
2129 "pad-removed",
2130 G_CALLBACK (stream_pad_removed_cb),
2131 stream,
2132 0);
2133
2134 stream->identity = gst_element_factory_make ("identity", NULL);
2135 if (stream->identity == NULL) {
2136 rb_debug ("unable to create identity");
2137 g_object_unref (stream);
2138 return NULL;
2139 }
2140
2141 stream->audioconvert = gst_element_factory_make ("audioconvert", NULL);
2142 if (stream->audioconvert == NULL) {
2143 rb_debug ("unable to create audio converter");
2144 g_object_unref (stream);
2145 return NULL;
2146 }
2147 gst_object_ref (stream->audioconvert);
2148
2149 stream->audioresample = gst_element_factory_make ("audioresample", NULL);
2150 if (stream->audioresample == NULL) {
2151 rb_debug ("unable to create audio resample");
2152 g_object_unref (stream);
2153 return NULL;
2154 }
2155 gst_object_ref (stream->audioresample);
2156
2157 stream->capsfilter = gst_element_factory_make ("capsfilter", NULL);
2158 if (stream->capsfilter == NULL) {
2159 rb_debug ("unable to create capsfilter");
2160 g_object_unref (stream);
2161 return NULL;
2162 }
2163 gst_object_ref (stream->capsfilter);
2164
2165 caps = gst_caps_new_simple ("audio/x-raw-int",
2166 "channels", G_TYPE_INT, 2,
2167 "rate", G_TYPE_INT, 44100,
2168 "width", G_TYPE_INT, 16,
2169 "depth", G_TYPE_INT, 16,
2170 NULL);
2171 g_object_set (stream->capsfilter, "caps", caps, NULL);
2172 gst_caps_unref (caps);
2173
2174 stream->volume = gst_element_factory_make ("volume", NULL);
2175 if (stream->volume == NULL) {
2176 rb_debug ("unable to create volume control");
2177 g_object_unref (stream);
2178 return NULL;
2179 }
2180 gst_object_ref (stream->volume);
2181
2182 g_signal_connect_object (stream->volume,
2183 "notify::volume",
2184 G_CALLBACK (volume_changed_cb),
2185 player, 0);
2186
2187 controller = gst_object_control_properties (G_OBJECT (stream->volume), "volume", NULL);
2188 if (controller == NULL) {
2189 rb_debug ("unable to create volume controller");
2190 g_object_unref (stream);
2191 return NULL;
2192 }
2193
2194 stream->fader = gst_interpolation_control_source_new ();
2195 gst_interpolation_control_source_set_interpolation_mode (stream->fader, GST_INTERPOLATE_LINEAR);
2196 gst_controller_set_control_source (controller, "volume", GST_CONTROL_SOURCE (stream->fader));
2197
2198 stream->preroll = gst_element_factory_make ("queue", NULL);
2199 if (stream->preroll == NULL) {
2200 rb_debug ("unable to create preroll queue");
2201 g_object_unref (stream);
2202 return NULL;
2203 }
2204 /* decode at least a second during prerolling, to hopefully avoid underruns.
2205 * we clear this when prerolling is finished. bump the max buffer count up
2206 * a bit (from 200) as with some formats it often takes more buffers to
2207 * make up a whole second. don't really want to remove it altogether, though.
2208 */
2209 g_object_set (stream->preroll,
2210 "min-threshold-time", GST_SECOND,
2211 "max-size-buffers", 1000,
2212 NULL);
2213
2214 gst_bin_add_many (GST_BIN (stream),
2215 stream->decoder,
2216 stream->identity,
2217 stream->audioconvert,
2218 stream->audioresample,
2219 stream->capsfilter,
2220 stream->preroll,
2221 stream->volume,
2222 NULL);
2223 gst_element_link_many (stream->audioconvert,
2224 stream->audioresample,
2225 stream->capsfilter,
2226 stream->preroll,
2227 stream->volume,
2228 NULL);
2229
2230 if (rb_debug_matches ("check-imperfect", __FILE__)) {
2231
2232 if (rb_debug_matches ("check-imperfect-timestamp", __FILE__)) {
2233 g_object_set (stream->identity, "check-imperfect-timestamp", TRUE, NULL);
2234 }
2235 if (rb_debug_matches ("check-imperfect-offset", __FILE__)) {
2236 g_object_set (stream->identity, "check-imperfect-offset", TRUE, NULL);
2237 }
2238 }
2239 stream->src_pad = gst_element_get_static_pad (stream->volume, "src");
2240
2241 /* link in any per-stream filters after the identity element, with an
2242 * audioconvert before each.
2243 */
2244 tail = stream->identity;
2245 g_signal_emit (player, signals[GET_STREAM_FILTERS], 0, uri, &stream_filters);
2246 if (stream_filters != NULL) {
2247 int i;
2248 for (i = 0; i < stream_filters->len; i++) {
2249 GValue *v = &g_array_index (stream_filters, GValue, i);
2250 GstElement *filter;
2251 GstElement *audioconvert;
2252
2253 audioconvert = gst_element_factory_make ("audioconvert", NULL);
2254 filter = GST_ELEMENT (g_value_get_object (v));
2255
2256 gst_bin_add_many (GST_BIN (stream), audioconvert, filter, NULL);
2257 gst_element_link_many (tail, audioconvert, filter, NULL);
2258 tail = filter;
2259 }
2260
2261 g_array_unref (stream_filters);
2262 }
2263 gst_element_link (tail, stream->audioconvert);
2264
2265 /* ghost the stream src pad up to the bin */
2266 stream->ghost_pad = gst_ghost_pad_new ("src", stream->src_pad);
2267 gst_element_add_pad (GST_ELEMENT (stream), stream->ghost_pad);
2268
2269 /* watch for EOS events using a pad probe */
2270 gst_pad_add_event_probe (stream->src_pad, (GCallback) stream_src_event_cb, stream);
2271
2272 /* use the pipeline bus even when not inside the pipeline (?) */
2273 gst_element_set_bus (GST_ELEMENT (stream), gst_element_get_bus (player->priv->pipeline));
2274
2275 return stream;
2276 }
2277
2278 /* starts playback for a stream.
2279 * - links to adder and unblocks
2280 * - if play_type is CROSSFADE:
2281 * - starts the fade in of the new stream
2282 * - starts the fade out of the old stream
2283 * - sets the stream to PLAYING state
2284 * - if play_type is WAIT_EOS:
2285 * - if something is playing, set the stream to wait-eos state
2286 * - otherwise, starts it
2287 * - if play_type is REPLACE:
2288 * - stops any existing stream
2289 * - starts the new stream
2290 */
2291 static gboolean
2292 actually_start_stream (RBXFadeStream *stream, GError **error)
2293 {
2294 RBPlayerGstXFade *player = stream->player;
2295 gboolean ret = TRUE;
2296 gboolean need_reap = FALSE;
2297 gboolean playing;
2298 GList *l;
2299 GList *to_fade;
2300
2301 rb_debug ("going to start playback for stream %s (play type %d, crossfade %" G_GINT64_FORMAT ") -> FADING_IN | PLAYING", stream->uri, stream->play_type, stream->crossfade);
2302 switch (stream->play_type) {
2303 case RB_PLAYER_PLAY_CROSSFADE:
2304
2305 to_fade = NULL;
2306 g_rec_mutex_lock (&player->priv->stream_list_lock);
2307 for (l = player->priv->streams; l != NULL; l = l->next) {
2308 RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2309
2310 if (pstream == stream)
2311 continue;
2312
2313 switch (pstream->state) {
2314 case FADING_IN:
2315 case PLAYING:
2316 rb_debug ("stream %s is playing; crossfading -> FADING_OUT", pstream->uri);
2317 to_fade = g_list_prepend (to_fade, g_object_ref (pstream));
2318 break;
2319
2320 case PAUSED:
2321 case WAITING_EOS:
2322 case SEEKING:
2323 case SEEKING_PAUSED:
2324 case PREROLLING:
2325 case PREROLL_PLAY:
2326 rb_debug ("stream %s is paused; replacing it", pstream->uri);
2327 pstream->state = PENDING_REMOVE;
2328 /* fall through */
2329 case PENDING_REMOVE:
2330 need_reap = TRUE;
2331 break;
2332
2333 default:
2334 break;
2335 }
2336 }
2337
2338 g_rec_mutex_unlock (&player->priv->stream_list_lock);
2339
2340 for (l = to_fade; l != NULL; l = l->next) {
2341 RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2342 double fade_out_start = 1.0f;
2343 gint64 fade_out_time = stream->crossfade;
2344
2345 switch (pstream->state) {
2346 case FADING_IN:
2347 /* fade out from where the fade in got up to */
2348 g_object_get (pstream->volume, "volume", &fade_out_start, NULL);
2349 fade_out_time = (gint64)(((double) stream->crossfade) * fade_out_start);
2350 /* fall through */
2351
2352 case PLAYING:
2353 start_stream_fade (pstream, fade_out_start, 0.0f, fade_out_time);
2354 pstream->state = FADING_OUT;
2355
2356 start_stream_fade (stream, 0.0f, 1.0f, stream->crossfade);
2357 break;
2358
2359 default:
2360 /* shouldn't happen, but ignore it if it does */
2361 break;
2362 }
2363
2364 g_object_unref (pstream);
2365 }
2366 g_list_free (to_fade);
2367
2368 if (stream->fading == FALSE) {
2369 GValue v = {0,};
2370
2371 rb_debug ("stream isn't fading; setting volume to 1.0");
2372 g_value_init (&v, G_TYPE_DOUBLE);
2373 g_value_set_double (&v, 1.0);
2374 if (gst_interpolation_control_source_set (stream->fader, 0, &v) == FALSE) {
2375 rb_debug ("controller didn't like our start point");
2376 }
2377 g_value_unset (&v);
2378 }
2379
2380 ret = link_and_unblock_stream (stream, error);
2381 break;
2382
2383 case RB_PLAYER_PLAY_AFTER_EOS:
2384
2385 g_rec_mutex_lock (&player->priv->stream_list_lock);
2386
2387 playing = FALSE;
2388 for (l = player->priv->streams; l != NULL; l = l->next) {
2389 RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2390 if (pstream == stream)
2391 continue;
2392
2393 switch (pstream->state) {
2394 case PLAYING:
2395 case FADING_IN:
2396 case FADING_OUT:
2397 rb_debug ("stream %s is already playing", pstream->uri);
2398 playing = TRUE;
2399 break;
2400 case PAUSED:
2401 rb_debug ("stream %s is paused; replacing it", pstream->uri);
2402 pstream->state = PENDING_REMOVE;
2403 case PENDING_REMOVE:
2404 need_reap = TRUE;
2405 break;
2406 default:
2407 break;
2408 }
2409 }
2410
2411 g_rec_mutex_unlock (&player->priv->stream_list_lock);
2412
2413 if (playing) {
2414 /* wait for current stream's EOS */
2415 rb_debug ("existing playing stream found; waiting for its EOS -> WAITING_EOS");
2416 stream->state = WAITING_EOS;
2417 stream->starting_eos = FALSE;
2418 } else {
2419 rb_debug ("no playing stream found, so starting immediately");
2420 ret = link_and_unblock_stream (stream, error);
2421 }
2422 break;
2423
2424 case RB_PLAYER_PLAY_REPLACE:
2425 /* replace any existing playing stream */
2426 g_rec_mutex_lock (&player->priv->stream_list_lock);
2427
2428 for (l = player->priv->streams; l != NULL; l = l->next) {
2429 RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2430 if (pstream == stream)
2431 continue;
2432
2433 switch (pstream->state) {
2434 case PLAYING:
2435 case PAUSED:
2436 case FADING_IN:
2437 case PENDING_REMOVE:
2438 /* kill this one */
2439 rb_debug ("stopping stream %s (replaced by new stream)", pstream->uri);
2440 need_reap = TRUE;
2441 pstream->state = PENDING_REMOVE;
2442 break;
2443
2444 default:
2445 /* let it go */
2446 break;
2447 }
2448 }
2449
2450 g_rec_mutex_unlock (&player->priv->stream_list_lock);
2451
2452 ret = link_and_unblock_stream (stream, error);
2453 break;
2454
2455 default:
2456 g_assert_not_reached ();
2457 }
2458
2459 if (need_reap) {
2460 schedule_stream_reap (player);
2461 }
2462
2463 return ret;
2464 }
2465
2466 /* called on a streaming thread when the stream src pad is blocked
2467 * (that is, when prerolling is complete). in some situations we
2468 * start playback immediately, otherwise we wait for something else
2469 * to happen.
2470 */
2471 static void
2472 stream_src_blocked_cb (GstPad *pad, gboolean blocked, RBXFadeStream *stream)
2473 {
2474 GError *error = NULL;
2475 gboolean start_stream = FALSE;
2476
2477 g_mutex_lock (&stream->lock);
2478 if (stream->src_blocked) {
2479 rb_debug ("stream %s already blocked", stream->uri);
2480 g_mutex_unlock (&stream->lock);
2481 return;
2482 }
2483 stream->src_blocked = TRUE;
2484
2485 g_object_set (stream->preroll,
2486 "min-threshold-time", G_GINT64_CONSTANT (0),
2487 "max-size-buffers", 200, /* back to normal value */
2488 NULL);
2489
2490 if (stream->use_buffering) {
2491 rb_debug ("stream %s requires buffering", stream->uri);
2492 switch (stream->state) {
2493 case PREROLL_PLAY:
2494 post_stream_playing_message (stream, TRUE);
2495 break;
2496 default:
2497 break;
2498 }
2499 g_mutex_unlock (&stream->lock);
2500 return;
2501 }
2502
2503 /* update stream state */
2504 switch (stream->state) {
2505 case PREROLLING:
2506 rb_debug ("stream %s is prerolled, not starting yet -> WAITING", stream->uri);
2507 stream->state = WAITING;
2508 break;
2509 case PREROLL_PLAY:
2510 rb_debug ("stream %s is prerolled, need to start it", stream->uri);
2511 start_stream = TRUE;
2512 break;
2513 default:
2514 rb_debug ("didn't expect to get preroll completion callback in this state (%d)", stream->state);
2515 break;
2516 }
2517
2518 g_mutex_unlock (&stream->lock);
2519
2520 if (start_stream == TRUE) {
2521 /* not sure this is actually an acceptable thing to do on a streaming thread.. */
2522 if (actually_start_stream (stream, &error) == FALSE) {
2523 emit_stream_error (stream, error);
2524 }
2525 }
2526 }
2527
2528 /*
2529 * starts prerolling for a stream.
2530 * since the stream isn't linked to anything yet, we
2531 * block the src pad. when the pad block callback
2532 * is called, prerolling is complete and the stream
2533 * can be linked and played immediately if required.
2534 *
2535 * must be called *without* the stream list lock?
2536 */
2537 static void
2538 preroll_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
2539 {
2540 GstStateChangeReturn state;
2541 gboolean unblock = FALSE;
2542 GstMessage *message;
2543 GstBus *bus;
2544
2545 gst_pad_set_blocked_async (stream->src_pad,
2546 TRUE,
2547 (GstPadBlockCallback) stream_src_blocked_cb,
2548 stream);
2549
2550 stream->emitted_playing = FALSE;
2551 stream->state = PREROLLING;
2552 state = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PAUSED);
2553 switch (state) {
2554 case GST_STATE_CHANGE_FAILURE:
2555 rb_debug ("preroll for stream %s failed (state change failed)", stream->uri);
2556 /* attempting to unblock here causes deadlock */
2557
2558 /* process bus messages in case we got a redirect for this stream */
2559 bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2560 message = gst_bus_pop (bus);
2561 while (message != NULL) {
2562 rb_player_gst_xfade_bus_cb (bus, message, player);
2563 gst_message_unref (message);
2564 message = gst_bus_pop (bus);
2565 }
2566 g_object_unref (bus);
2567 break;
2568
2569 case GST_STATE_CHANGE_NO_PREROLL:
2570 rb_debug ("no preroll for stream %s, setting to PLAYING instead?", stream->uri);
2571 gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
2572 break;
2573 case GST_STATE_CHANGE_SUCCESS:
2574 case GST_STATE_CHANGE_ASYNC:
2575 /* uridecodebin returns SUCCESS from state changes when streaming, so we can't
2576 * use that to figure out what to do next. instead, we wait for pads to be added
2577 * and for our pad block callbacks to be called.
2578 */
2579 break;
2580 default:
2581 g_assert_not_reached();
2582 }
2583
2584 if (unblock) {
2585 rb_debug ("unblocking stream source pad");
2586 gst_pad_set_blocked_async (stream->src_pad,
2587 FALSE,
2588 NULL,
2589 NULL);
2590 }
2591 }
2592
2593 /*
2594 * returns the RBXFadeStream, playback position, and duration of the current
2595 * playing stream.
2596 */
2597 static gboolean
2598 get_times_and_stream (RBPlayerGstXFade *player, RBXFadeStream **pstream, gint64 *pos, gint64 *duration)
2599 {
2600 gboolean got_time = FALSE;
2601 gboolean buffering = FALSE;
2602 RBXFadeStream *stream;
2603
2604 if (player->priv->pipeline == NULL)
2605 return FALSE;
2606
2607 g_rec_mutex_lock (&player->priv->stream_list_lock);
2608
2609 /* first look for a network stream that is buffering during preroll */
2610 stream = find_stream_by_state (player, PREROLLING | PREROLL_PLAY);
2611 if (stream != NULL) {
2612 if (stream->emitted_fake_playing == FALSE) {
2613 g_object_unref (stream);
2614 stream = NULL;
2615 } else {
2616 rb_debug ("found buffering stream %s as current", stream->uri);
2617 buffering = TRUE;
2618 }
2619 }
2620
2621 /* otherwise, the stream that is playing */
2622 if (stream == NULL) {
2623 stream = find_stream_by_state (player, FADING_IN | PLAYING | FADING_OUT_PAUSED | PAUSED | PENDING_REMOVE | REUSING);
2624 }
2625 g_rec_mutex_unlock (&player->priv->stream_list_lock);
2626
2627 if (stream != NULL) {
2628 if (pstream != NULL) {
2629 *pstream = stream;
2630 }
2631
2632 if (pos != NULL) {
2633 if (buffering) {
2634 *pos = 0;
2635 } else if (stream->state == PAUSED) {
2636 GstFormat format = GST_FORMAT_TIME;
2637 *pos = -1;
2638
2639 gst_element_query_position (stream->volume, &format, pos);
2640 } else {
2641 /* for playing streams, we subtract the current output position
2642 * (a running counter generated by the adder) from the position
2643 * at which we started playback.
2644 */
2645 GstFormat format = GST_FORMAT_TIME;
2646 *pos = -1;
2647 gst_element_query_position (player->priv->pipeline, &format, pos);
2648 if (*pos != -1) {
2649 *pos -= stream->base_time;
2650 } else {
2651 rb_debug ("position query failed");
2652 }
2653 }
2654 }
2655
2656 if (duration != NULL) {
2657 GstFormat format = GST_FORMAT_TIME;
2658 *duration = -1;
2659 /* queries are supposed to go to sinks, but the closest thing we
2660 * have in the stream bin is the volume element, which is the last
2661 * linked element.
2662 */
2663 gst_element_query_duration (stream->volume, &format, duration);
2664 }
2665 got_time = TRUE;
2666 if (pstream == NULL) {
2667 g_object_unref (stream);
2668 }
2669 } else {
2670 rb_debug ("not playing");
2671 }
2672
2673 return got_time;
2674 }
2675
2676 static gboolean
2677 tick_timeout (RBPlayerGstXFade *player)
2678 {
2679 gint64 pos = -1;
2680 gint64 duration = -1;
2681 RBXFadeStream *stream = NULL;
2682
2683 if (get_times_and_stream (player, &stream, &pos, &duration)) {
2684 _rb_player_emit_tick (RB_PLAYER (player), stream->stream_data, pos, duration);
2685 g_object_unref (stream);
2686 }
2687
2688 return TRUE;
2689 }
2690
2691 static gboolean
2692 emit_volume_changed_idle (RBPlayerGstXFade *player)
2693 {
2694 double vol;
2695
2696 if (gst_element_implements_interface (player->priv->volume_handler, GST_TYPE_STREAM_VOLUME)) {
2697 vol = gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
2698 GST_STREAM_VOLUME_FORMAT_CUBIC);
2699 } else {
2700 vol = player->priv->cur_volume;
2701 }
2702
2703 _rb_player_emit_volume_changed (RB_PLAYER (player), vol);
2704 return FALSE;
2705 }
2706
2707 static void
2708 stream_volume_changed (GObject *element, GParamSpec *pspec, RBPlayerGstXFade *player)
2709 {
2710 double v;
2711
2712 g_object_get (element, "volume", &v, NULL);
2713 player->priv->cur_volume = v;
2714
2715 g_idle_add ((GSourceFunc) emit_volume_changed_idle, player);
2716 }
2717
2718 /*
2719 * output sink + adder pipeline:
2720 *
2721 * outputcaps = audio/x-raw-int,channels=2,rate=44100,width=16,depth=16
2722 * outputbin = outputcaps ! volume ! filterbin ! audioconvert ! audioresample ! tee ! queue ! audiosink
2723 * silencebin = audiotestsrc wave=silence ! outputcaps
2724 *
2725 * pipeline = silencebin ! adder ! outputbin
2726 *
2727 * the tee in output bin has branches attached to it using the
2728 * RBPlayerGstTee interface. filterbin contains elements inserted
2729 * using the RBPlayerGstFilter interface.
2730 *
2731 * silencebin is there for two reasons:
2732 * - lets us start the sink without having any streams playing
2733 * - probably helps keep things from falling over between streams
2734 */
2735
2736 static void
2737 add_bus_watch (RBPlayerGstXFade *player)
2738 {
2739 GstBus *bus;
2740
2741 bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2742 player->priv->bus_watch_id = gst_bus_add_watch (bus, (GstBusFunc) rb_player_gst_xfade_bus_cb, player);
2743 gst_object_unref (bus);
2744 }
2745
2746 static gboolean
2747 start_sink_locked (RBPlayerGstXFade *player, GList **messages, GError **error)
2748 {
2749 GstStateChangeReturn sr;
2750 gboolean waiting;
2751 GError *generic_error = NULL;
2752 GstBus *bus;
2753
2754 g_set_error (&generic_error,
2755 RB_PLAYER_ERROR,
2756 RB_PLAYER_ERROR_INTERNAL, /* ? */
2757 _("Failed to open output device"));
2758
2759 rb_debug ("starting sink");
2760
2761 /* first, start the output bin.
2762 * this won't preroll until we start the silence bin.
2763 */
2764 sr = gst_element_set_state (player->priv->outputbin, GST_STATE_PAUSED);
2765 if (sr == GST_STATE_CHANGE_FAILURE) {
2766 rb_debug ("output bin state change failed");
2767 g_propagate_error (error, generic_error);
2768 return FALSE;
2769 }
2770
2771 /* then the adder */
2772 sr = gst_element_set_state (player->priv->adder, GST_STATE_PAUSED);
2773 if (sr == GST_STATE_CHANGE_FAILURE) {
2774 rb_debug ("adder state change failed");
2775 g_propagate_error (error, generic_error);
2776 return FALSE;
2777 }
2778
2779 /* then the silence bin */
2780 sr = gst_element_set_state (player->priv->silencebin, GST_STATE_PAUSED);
2781 if (sr == GST_STATE_CHANGE_FAILURE) {
2782 rb_debug ("silence bin state change failed");
2783 g_propagate_error (error, generic_error);
2784 return FALSE;
2785 }
2786
2787 /* now wait for everything to finish */
2788 waiting = TRUE;
2789 bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2790 while (waiting) {
2791 GstMessage *message;
2792 GstState oldstate;
2793 GstState newstate;
2794 GstState pending;
2795
2796 message = gst_bus_timed_pop (bus, GST_SECOND * 5);
2797 if (message == NULL) {
2798 rb_debug ("sink is taking too long to start..");
2799 g_propagate_error (error, generic_error);
2800 gst_object_unref (bus);
2801 return FALSE;
2802 }
2803
2804 switch (GST_MESSAGE_TYPE (message)) {
2805 case GST_MESSAGE_ERROR:
2806 {
2807 char *debug;
2808 GError *gst_error = NULL;
2809 GstObject *message_src;
2810 RBXFadeStream *stream;
2811
2812 /* we only want to process errors from the sink here.
2813 * errors from streams should go to the normal message handler.
2814 */
2815 message_src = GST_MESSAGE_SRC (message);
2816 stream = find_stream_by_element (player, GST_ELEMENT (message_src));
2817 if (stream != NULL) {
2818 rb_debug ("got an error from a stream; passing it to the bus handler");
2819 *messages = g_list_append (*messages, gst_message_ref (message));
2820 g_object_unref (stream);
2821 } else {
2822 gst_message_parse_error (message, &gst_error, &debug);
2823 rb_debug ("got error message: %s (%s)", gst_error->message, debug);
2824 gst_message_unref (message);
2825 g_free (debug);
2826
2827 if (error != NULL && *error == NULL) {
2828 /* Translators: the parameter here is an error message */
2829 g_set_error (error,
2830 RB_PLAYER_ERROR,
2831 RB_PLAYER_ERROR_INTERNAL, /* ? */
2832 _("Failed to open output device: %s"),
2833 gst_error->message);
2834 }
2835 g_error_free (gst_error);
2836 g_error_free (generic_error);
2837
2838 gst_element_set_state (player->priv->outputbin, GST_STATE_NULL);
2839 gst_element_set_state (player->priv->adder, GST_STATE_NULL);
2840 gst_element_set_state (player->priv->silencebin, GST_STATE_NULL);
2841 gst_object_unref (bus);
2842 return FALSE;
2843 }
2844 }
2845 break;
2846
2847 case GST_MESSAGE_STATE_CHANGED:
2848 {
2849 gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
2850 if (newstate == GST_STATE_PAUSED && pending == GST_STATE_VOID_PENDING) {
2851 if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->outputbin)) {
2852 rb_debug ("outputbin is now PAUSED");
2853 waiting = FALSE;
2854 } else if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->adder)) {
2855 rb_debug ("adder is now PAUSED");
2856 } else if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->silencebin)) {
2857 rb_debug ("silencebin is now PAUSED");
2858 }
2859 }
2860 }
2861 break;
2862
2863 default:
2864 /* save the message to pass to the bus callback once we've dropped
2865 * the sink lock.
2866 */
2867 *messages = g_list_append (*messages, gst_message_ref (message));
2868 break;
2869 }
2870
2871 gst_message_unref (message);
2872 }
2873 gst_object_unref (bus);
2874
2875 /* if the sink provides a 'volume' property, use that to control output volume */
2876 player->priv->volume_handler = rb_player_gst_find_element_with_property (player->priv->sink, "volume");
2877 if (player->priv->volume_handler == NULL) {
2878 rb_debug ("sink doesn't provide volume control, using volume element");
2879 player->priv->volume_handler = g_object_ref (player->priv->volume);
2880 } else if (player->priv->volume_applied == 0) {
2881 /* ignore the initial volume setting, allowing the
2882 * sink to restore its own volume.
2883 */
2884 player->priv->volume_applied = 1;
2885 }
2886
2887 /* if there has been a volume change that we haven't applied, apply it now */
2888 if (player->priv->volume_applied < player->priv->volume_changed) {
2889 g_object_set (player->priv->volume_handler, "volume", player->priv->cur_volume, NULL);
2890 player->priv->volume_applied = player->priv->volume_changed;
2891 }
2892
2893 g_signal_connect_object (player->priv->volume_handler,
2894 "notify::volume",
2895 G_CALLBACK (stream_volume_changed),
2896 player, 0);
2897
2898
2899 sr = gst_element_set_state (player->priv->silencebin, GST_STATE_PLAYING);
2900 if (sr == GST_STATE_CHANGE_FAILURE) {
2901 rb_debug ("silence bin state change failed");
2902 g_propagate_error (error, generic_error);
2903 return FALSE;
2904 }
2905
2906 sr = gst_element_set_state (player->priv->adder, GST_STATE_PLAYING);
2907 if (sr == GST_STATE_CHANGE_FAILURE) {
2908 rb_debug ("adder state change failed");
2909 g_propagate_error (error, generic_error);
2910 return FALSE;
2911 }
2912
2913 sr = gst_element_set_state (player->priv->outputbin, GST_STATE_PLAYING);
2914 if (sr == GST_STATE_CHANGE_FAILURE) {
2915 rb_debug ("output bin state change failed");
2916 g_propagate_error (error, generic_error);
2917 return FALSE;
2918 }
2919
2920 rb_debug ("sink playing");
2921 player->priv->sink_state = SINK_PLAYING;
2922
2923 /* set the pipeline to PLAYING so it selects a clock */
2924 gst_element_set_state (player->priv->pipeline, GST_STATE_PLAYING);
2925
2926 /* now that the sink is running, start polling for playing position.
2927 * might want to replace this with a complicated set of pad probes
2928 * to avoid polling, but duration queries on the sink are better
2929 * as they account for internal buffering etc. maybe there's a way
2930 * to account for that in a pad probe callback on the sink's sink pad?
2931 */
2932 if (player->priv->tick_timeout_id == 0) {
2933 gint ms_period = 1000 / RB_PLAYER_GST_XFADE_TICK_HZ;
2934 player->priv->tick_timeout_id =
2935 g_timeout_add (ms_period,
2936 (GSourceFunc) tick_timeout,
2937 player);
2938 }
2939 return TRUE;
2940 }
2941
2942 static gboolean
2943 start_sink (RBPlayerGstXFade *player, GError **error)
2944 {
2945 GList *messages = NULL;
2946 GList *t;
2947 GstBus *bus;
2948 gboolean ret;
2949
2950 g_rec_mutex_lock (&player->priv->sink_lock);
2951 switch (player->priv->sink_state) {
2952 case SINK_NULL:
2953 g_assert_not_reached ();
2954 break;
2955
2956 case SINK_STOPPED:
2957 /* prevent messages from being processed by the main thread while we're starting the sink */
2958 g_source_remove (player->priv->bus_watch_id);
2959 ret = start_sink_locked (player, &messages, error);
2960 add_bus_watch (player);
2961 break;
2962
2963 case SINK_PLAYING:
2964 ret = TRUE;
2965 break;
2966
2967 default:
2968 g_assert_not_reached ();
2969 }
2970 g_rec_mutex_unlock (&player->priv->sink_lock);
2971
2972 bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2973 for (t = messages; t != NULL; t = t->next) {
2974 rb_player_gst_xfade_bus_cb (bus, t->data, player);
2975 }
2976 gst_object_unref (bus);
2977
2978 rb_list_destroy_free (messages, (GDestroyNotify) gst_mini_object_unref);
2979 return ret;
2980 }
2981
2982 static gboolean
2983 stop_sink (RBPlayerGstXFade *player)
2984 {
2985 GstStateChangeReturn sr;
2986
2987 switch (player->priv->sink_state) {
2988 case SINK_PLAYING:
2989 rb_debug ("stopping sink");
2990
2991 if (player->priv->tick_timeout_id != 0) {
2992 g_source_remove (player->priv->tick_timeout_id);
2993 player->priv->tick_timeout_id = 0;
2994 }
2995
2996 sr = gst_element_set_state (player->priv->outputbin, GST_STATE_READY);
2997 if (sr == GST_STATE_CHANGE_FAILURE) {
2998 rb_debug ("couldn't stop output bin");
2999 return FALSE;
3000 }
3001
3002 sr = gst_element_set_state (player->priv->adder, GST_STATE_READY);
3003 if (sr == GST_STATE_CHANGE_FAILURE) {
3004 rb_debug ("couldn't stop adder");
3005 return FALSE;
3006 }
3007
3008 sr = gst_element_set_state (player->priv->silencebin, GST_STATE_READY);
3009 if (sr == GST_STATE_CHANGE_FAILURE) {
3010 rb_debug ("couldn't stop silence bin");
3011 return FALSE;
3012 }
3013
3014 /* try stopping the sink, but don't worry if we can't */
3015 sr = gst_element_set_state (player->priv->sink, GST_STATE_NULL);
3016 if (sr == GST_STATE_CHANGE_FAILURE) {
3017 rb_debug ("couldn't set audio sink to NULL state");
3018 }
3019
3020 if (player->priv->volume_handler) {
3021 g_object_unref (player->priv->volume_handler);
3022 player->priv->volume_handler = NULL;
3023 }
3024
3025 /* set the pipeline to READY so we can make it select a clock when we
3026 * start the sink again. everything inside the pipeline has its state
3027 * locked, so this doesn't affect anything else.
3028 */
3029 gst_element_set_state (player->priv->pipeline, GST_STATE_READY);
3030
3031 player->priv->sink_state = SINK_STOPPED;
3032 break;
3033
3034 case SINK_STOPPED:
3035 case SINK_NULL:
3036 break;
3037 }
3038
3039 return TRUE;
3040 }
3041
3042
3043 static gboolean
3044 create_sink (RBPlayerGstXFade *player, GError **error)
3045 {
3046 const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
3047 GstElement *audiotestsrc;
3048 GstElement *audioconvert;
3049 GstElement *audioresample;
3050 GstElement *capsfilter;
3051 GstElement *queue;
3052 GstCaps *caps;
3053 GstPad *filterpad;
3054 GstPad *outputghostpad;
3055 GstPad *ghostpad;
3056 GstPad *reqpad;
3057 GstPad *addersrcpad;
3058 GstPadLinkReturn plr;
3059 GList *l;
3060 int i;
3061
3062 if (player->priv->sink_state != SINK_NULL)
3063 return TRUE;
3064
3065 /* set filter caps.
3066 * 44100Hz is about the most reasonable thing to use;
3067 * we have audioconvert+audioresample afterwards in
3068 * case the output device doesn't actually support
3069 * that rate.
3070 */
3071 caps = gst_caps_new_simple ("audio/x-raw-int",
3072 "channels", G_TYPE_INT, 2,
3073 "rate", G_TYPE_INT, 44100,
3074 "width", G_TYPE_INT, 16,
3075 "depth", G_TYPE_INT, 16,
3076 NULL);
3077
3078 player->priv->pipeline = gst_pipeline_new ("rbplayer");
3079 add_bus_watch (player);
3080 g_object_notify (G_OBJECT (player), "bus");
3081
3082 player->priv->outputbin = gst_bin_new ("outputbin");
3083 gst_element_set_locked_state (player->priv->outputbin, TRUE);
3084 player->priv->adder = gst_element_factory_make ("adder", "outputadder");
3085 player->priv->capsfilter = gst_element_factory_make ("capsfilter", "outputcapsfilter");
3086 audioconvert = gst_element_factory_make ("audioconvert", "outputconvert");
3087 audioresample = gst_element_factory_make ("audioresample", "outputresample");
3088 player->priv->tee = gst_element_factory_make ("tee", "outputtee");
3089 queue = gst_element_factory_make ("queue", NULL);
3090 player->priv->volume = gst_element_factory_make ("volume", "outputvolume");
3091 player->priv->filterbin = rb_gst_create_filter_bin ();
3092 capsfilter = gst_element_factory_make ("capsfilter", NULL);
3093 if (player->priv->pipeline == NULL ||
3094 player->priv->adder == NULL ||
3095 player->priv->capsfilter == NULL ||
3096 audioconvert == NULL ||
3097 audioresample == NULL ||
3098 player->priv->tee == NULL ||
3099 queue == NULL ||
3100 player->priv->volume == NULL ||
3101 player->priv->filterbin == NULL ||
3102 capsfilter == NULL) {
3103 /* we could include the element name in the error message,
3104 * but these are all fundamental elements that are always
3105 * available.
3106 */
3107 g_set_error (error,
3108 RB_PLAYER_ERROR,
3109 RB_PLAYER_ERROR_GENERAL,
3110 _("Failed to create GStreamer element; check your installation"));
3111 return FALSE;
3112 }
3113
3114 for (i = 0; i < G_N_ELEMENTS (try_sinks); i++) {
3115 player->priv->sink = rb_player_gst_try_audio_sink (try_sinks[i], NULL);
3116 if (player->priv->sink != NULL) {
3117 break;
3118 }
3119 }
3120 if (player->priv->sink == NULL) {
3121 g_set_error (error,
3122 RB_PLAYER_ERROR,
3123 RB_PLAYER_ERROR_GENERAL,
3124 _("Failed to create audio output element; check your installation"));
3125 return FALSE;
3126 }
3127
3128 g_object_set (player->priv->capsfilter, "caps", caps, NULL);
3129 g_object_set (capsfilter, "caps", caps, NULL);
3130
3131 g_object_set (queue, "max-size-buffers", 10, NULL);
3132
3133 gst_bin_add_many (GST_BIN (player->priv->outputbin),
3134 player->priv->capsfilter,
3135 player->priv->volume,
3136 player->priv->filterbin,
3137 audioconvert,
3138 audioresample,
3139 capsfilter,
3140 player->priv->tee,
3141 queue,
3142 player->priv->sink,
3143 NULL);
3144 if (gst_element_link_many (player->priv->capsfilter,
3145 player->priv->volume,
3146 player->priv->filterbin,
3147 audioconvert,
3148 audioresample,
3149 capsfilter,
3150 player->priv->tee,
3151 queue,
3152 player->priv->sink,
3153 NULL) == FALSE) {
3154 g_set_error (error,
3155 RB_PLAYER_ERROR,
3156 RB_PLAYER_ERROR_GENERAL,
3157 _("Failed to link GStreamer pipeline; check your installation"));
3158 return FALSE;
3159 }
3160
3161 filterpad = gst_element_get_static_pad (player->priv->capsfilter, "sink");
3162 outputghostpad = gst_ghost_pad_new ("sink", filterpad);
3163 gst_element_add_pad (player->priv->outputbin, outputghostpad);
3164 gst_object_unref (filterpad);
3165
3166 /* create silence bin */
3167 player->priv->silencebin = gst_bin_new ("silencebin");
3168 audiotestsrc = gst_element_factory_make ("audiotestsrc", "silence");
3169 g_object_set (audiotestsrc, "wave", 4, NULL);
3170
3171 audioconvert = gst_element_factory_make ("audioconvert", "silenceconvert");
3172
3173 capsfilter = gst_element_factory_make ("capsfilter", "silencecapsfilter");
3174 g_object_set (capsfilter, "caps", caps, NULL);
3175 gst_caps_unref (caps);
3176
3177 if (audiotestsrc == NULL ||
3178 audioconvert == NULL ||
3179 capsfilter == NULL) {
3180 g_set_error (error,
3181 RB_PLAYER_ERROR,
3182 RB_PLAYER_ERROR_GENERAL,
3183 _("Failed to create GStreamer element; check your installation"));
3184 return FALSE;
3185 }
3186
3187 gst_bin_add_many (GST_BIN (player->priv->silencebin),
3188 audiotestsrc,
3189 audioconvert,
3190 capsfilter,
3191 NULL);
3192 if (gst_element_link_many (audiotestsrc,
3193 audioconvert,
3194 capsfilter,
3195 NULL) == FALSE) {
3196 g_set_error (error,
3197 RB_PLAYER_ERROR,
3198 RB_PLAYER_ERROR_GENERAL,
3199 _("Failed to link GStreamer pipeline; check your installation"));
3200 return FALSE;
3201 }
3202
3203 filterpad = gst_element_get_static_pad (capsfilter, "src");
3204 ghostpad = gst_ghost_pad_new (NULL, filterpad);
3205 gst_element_add_pad (player->priv->silencebin, ghostpad);
3206 gst_object_unref (filterpad);
3207
3208 /* assemble stuff:
3209 * - add everything to the pipeline
3210 * - link adder to output bin
3211 * - link silence bin to adder
3212 */
3213 gst_bin_add_many (GST_BIN (player->priv->pipeline),
3214 player->priv->adder,
3215 player->priv->outputbin,
3216 player->priv->silencebin,
3217 NULL);
3218
3219 addersrcpad = gst_element_get_static_pad (player->priv->adder, "src");
3220 plr = gst_pad_link (addersrcpad, outputghostpad);
3221 if (plr != GST_PAD_LINK_OK) {
3222 g_set_error (error,
3223 RB_PLAYER_ERROR,
3224 RB_PLAYER_ERROR_GENERAL,
3225 _("Failed to link GStreamer pipeline; check your installation"));
3226 return FALSE;
3227 }
3228
3229 reqpad = gst_element_get_request_pad (player->priv->adder, "sink%d");
3230 if (reqpad == NULL) {
3231 g_set_error (error,
3232 RB_PLAYER_ERROR,
3233 RB_PLAYER_ERROR_GENERAL,
3234 _("Failed to link GStreamer pipeline; check your installation"));
3235 return FALSE;
3236 }
3237
3238 plr = gst_pad_link (ghostpad, reqpad);
3239 if (plr != GST_PAD_LINK_OK) {
3240 g_set_error (error,
3241 RB_PLAYER_ERROR,
3242 RB_PLAYER_ERROR_GENERAL,
3243 _("Failed to link GStreamer pipeline; check your installation"));
3244 return FALSE;
3245 }
3246
3247 /* add any tees and filters that were waiting for us */
3248 for (l = player->priv->waiting_tees; l != NULL; l = g_list_next (l)) {
3249 rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (player), GST_ELEMENT (l->data));
3250 }
3251 g_list_free (player->priv->waiting_tees);
3252 player->priv->waiting_tees = NULL;
3253
3254 for (l = player->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
3255 rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER (player), GST_ELEMENT (l->data));
3256 }
3257 g_list_free (player->priv->waiting_filters);
3258 player->priv->waiting_filters = NULL;
3259
3260 player->priv->sink_state = SINK_STOPPED;
3261 return TRUE;
3262 }
3263
3264
3265
3266 static gboolean
3267 rb_player_gst_xfade_open (RBPlayer *iplayer,
3268 const char *uri,
3269 gpointer stream_data,
3270 GDestroyNotify stream_data_destroy,
3271 GError **error)
3272 {
3273 RBXFadeStream *stream;
3274 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3275 gboolean reused = FALSE;
3276 GList *t;
3277
3278 /* create sink if we don't already have one */
3279 if (create_sink (player, error) == FALSE)
3280 return FALSE;
3281
3282 /* see if anyone wants us to reuse an existing stream */
3283 g_rec_mutex_lock (&player->priv->stream_list_lock);
3284 for (t = player->priv->streams; t != NULL; t = t->next) {
3285 RBXFadeStream *stream = (RBXFadeStream *)t->data;
3286
3287 switch (stream->state) {
3288 case WAITING:
3289 case PENDING_REMOVE:
3290 case REUSING:
3291 case SEEKING:
3292 case SEEKING_PAUSED:
3293 case SEEKING_EOS:
3294 case PREROLLING:
3295 case PREROLL_PLAY:
3296 break;
3297
3298 case PLAYING:
3299 case FADING_IN:
3300 case FADING_OUT:
3301 case FADING_OUT_PAUSED:
3302 case WAITING_EOS:
3303 case PAUSED:
3304 g_signal_emit (player,
3305 signals[CAN_REUSE_STREAM], 0,
3306 uri, stream->uri, GST_ELEMENT (stream),
3307 &reused);
3308 break;
3309 }
3310
3311 if (reused) {
3312 rb_debug ("reusing stream %s for new stream %s", stream->uri, uri);
3313 stream->state = REUSING;
3314 stream->new_uri = g_strdup (uri);
3315 stream->new_stream_data = stream_data;
3316 stream->new_stream_data_destroy = stream_data_destroy;
3317
3318 /* move the stream to the front of the list so it'll be started when
3319 * _play is called (it's probably already there, but just in case..)
3320 */
3321 player->priv->streams = g_list_remove (player->priv->streams, stream);
3322 player->priv->streams = g_list_prepend (player->priv->streams, stream);
3323 break;
3324 }
3325 }
3326 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3327 if (reused) {
3328 return TRUE;
3329 }
3330
3331 /* construct new stream */
3332 stream = create_stream (player, uri, stream_data, stream_data_destroy);
3333 if (stream == NULL) {
3334 rb_debug ("unable to create pipeline to play %s", uri);
3335 g_set_error (error,
3336 RB_PLAYER_ERROR,
3337 RB_PLAYER_ERROR_GENERAL,
3338 _("Failed to create GStreamer pipeline to play %s"),
3339 uri);
3340 return FALSE;
3341 }
3342
3343 g_rec_mutex_lock (&player->priv->stream_list_lock);
3344 player->priv->streams = g_list_prepend (player->priv->streams, stream);
3345 dump_stream_list (player);
3346 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3347
3348 /* start prerolling it */
3349 preroll_stream (player, stream);
3350
3351 return TRUE;
3352 }
3353
3354 static gboolean
3355 stop_sink_later (RBPlayerGstXFade *player)
3356 {
3357 g_rec_mutex_lock (&player->priv->sink_lock);
3358 player->priv->stop_sink_id = 0;
3359 if (g_atomic_int_get (&player->priv->linked_streams) == 0) {
3360 stop_sink (player);
3361 }
3362 g_rec_mutex_unlock (&player->priv->sink_lock);
3363
3364 return FALSE;
3365 }
3366
3367 static void
3368 maybe_stop_sink (RBPlayerGstXFade *player)
3369 {
3370 g_rec_mutex_lock (&player->priv->sink_lock);
3371 if (player->priv->stop_sink_id == 0) {
3372 player->priv->stop_sink_id =
3373 g_timeout_add (1000,
3374 (GSourceFunc) stop_sink_later,
3375 player);
3376 }
3377 g_rec_mutex_unlock (&player->priv->sink_lock);
3378 }
3379
3380 static gboolean
3381 rb_player_gst_xfade_close (RBPlayer *iplayer, const char *uri, GError **error)
3382 {
3383 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3384 gboolean ret = TRUE;
3385
3386 if (uri == NULL) {
3387 GList *list;
3388 GList *l;
3389
3390 /* need to copy the list as unlink_and_dispose_stream modifies it */
3391 g_rec_mutex_lock (&player->priv->stream_list_lock);
3392 list = g_list_copy (player->priv->streams);
3393 for (l = list; l != NULL; l = l->next) {
3394 RBXFadeStream *stream = (RBXFadeStream *)l->data;
3395 g_object_ref (stream);
3396 }
3397 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3398
3399 for (l = list; l != NULL; l = l->next) {
3400 RBXFadeStream *stream = (RBXFadeStream *)l->data;
3401 unlink_and_dispose_stream (player, stream);
3402 g_object_unref (stream);
3403 }
3404 g_list_free (list);
3405 } else {
3406 /* just stop and close the stream for the specified uri */
3407 RBXFadeStream *stream;
3408
3409 g_rec_mutex_lock (&player->priv->stream_list_lock);
3410 stream = find_stream_by_uri (player, uri);
3411 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3412
3413 if (stream != NULL) {
3414 unlink_and_dispose_stream (player, stream);
3415 g_object_unref (stream);
3416 } else {
3417 rb_debug ("can't find stream for %s", uri);
3418 /* XXX set error ?*/
3419 ret = FALSE;
3420 }
3421 }
3422
3423 return ret;
3424 }
3425
3426
3427 static gboolean
3428 rb_player_gst_xfade_opened (RBPlayer *iplayer)
3429 {
3430 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3431 RBXFadeStream *stream;
3432 gboolean opened = FALSE;
3433
3434 /* maybe replace this with just a flag somewhere? */
3435
3436 g_rec_mutex_lock (&player->priv->stream_list_lock);
3437
3438 stream = find_stream_by_state (player, PREROLLING | PREROLL_PLAY | WAITING_EOS | WAITING | FADING_IN | PLAYING | PAUSED);
3439 if (stream != NULL) {
3440 opened = TRUE;
3441 g_object_unref (stream);
3442 }
3443
3444 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3445
3446 return opened;
3447 }
3448
3449 static gboolean
3450 rb_player_gst_xfade_play (RBPlayer *iplayer,
3451 RBPlayerPlayType play_type,
3452 gint64 crossfade,
3453 GError **error)
3454 {
3455 RBXFadeStream *stream;
3456 int stream_state;
3457 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3458 gboolean ret = TRUE;
3459
3460 g_rec_mutex_lock (&player->priv->stream_list_lock);
3461
3462 /* is there anything to play? */
3463 if (player->priv->streams == NULL) {
3464 g_set_error (error,
3465 RB_PLAYER_ERROR,
3466 RB_PLAYER_ERROR_GENERAL,
3467 "Nothing to play"); /* should never happen */
3468
3469 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3470 return FALSE;
3471 }
3472
3473 stream = g_list_first (player->priv->streams)->data;
3474 g_object_ref (stream);
3475 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3476
3477 /* make sure the sink is playing */
3478 if (start_sink (player, error) == FALSE) {
3479 g_object_unref (stream);
3480 return FALSE;
3481 }
3482
3483 g_mutex_lock (&stream->lock);
3484
3485 rb_debug ("playing stream %s, play type %d, crossfade %" G_GINT64_FORMAT, stream->uri, play_type, crossfade);
3486
3487 /* handle transitional states while holding the lock, and handle states that
3488 * require action outside it (lock precedence, mostly)
3489 */
3490 switch (stream->state) {
3491 case PREROLLING:
3492 case PREROLL_PLAY:
3493 rb_debug ("stream %s is prerolling; will start playback once prerolling is complete -> PREROLL_PLAY", stream->uri);
3494 stream->play_type = play_type;
3495 stream->crossfade = crossfade;
3496 stream->state = PREROLL_PLAY;
3497 break;
3498
3499 case SEEKING_PAUSED:
3500 rb_debug ("unpausing seeking stream %s", stream->uri);
3501 stream->state = SEEKING;
3502 break;
3503
3504 case PENDING_REMOVE:
3505 rb_debug ("hmm, can't play streams in PENDING_REMOVE state..");
3506 break;
3507
3508 default:
3509 break;
3510 }
3511
3512 stream_state = stream->state;
3513 g_mutex_unlock (&stream->lock);
3514
3515 /* is the head stream already playing? */
3516 switch (stream_state) {
3517 case FADING_IN:
3518 case FADING_OUT:
3519 case FADING_OUT_PAUSED:
3520 case PLAYING:
3521 case SEEKING:
3522 case SEEKING_EOS:
3523 rb_debug ("stream %s is already playing", stream->uri);
3524 _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
3525 break;
3526
3527 case PAUSED:
3528 rb_debug ("unpausing stream %s", stream->uri);
3529 start_stream_fade (stream, 0.0f, 1.0f, PAUSE_FADE_LENGTH);
3530 ret = link_and_unblock_stream (stream, error);
3531 break;
3532
3533 case WAITING_EOS:
3534 case WAITING:
3535 stream->play_type = play_type;
3536 stream->crossfade = crossfade;
3537 ret = actually_start_stream (stream, error);
3538 break;
3539
3540 case REUSING:
3541 switch (play_type) {
3542 case RB_PLAYER_PLAY_REPLACE:
3543 case RB_PLAYER_PLAY_CROSSFADE:
3544 /* probably should split this into two states.. */
3545 if (stream->src_blocked) {
3546 rb_debug ("reusing and restarting paused stream %s", stream->uri);
3547 reuse_stream (stream);
3548 ret = link_and_unblock_stream (stream, error);
3549 } else {
3550 rb_debug ("unlinking stream %s for reuse", stream->uri);
3551 unlink_and_block_stream (stream);
3552 }
3553 break;
3554 case RB_PLAYER_PLAY_AFTER_EOS:
3555 rb_debug ("waiting for EOS before reusing stream %s", stream->uri);
3556 break;
3557 }
3558 break;
3559
3560 default:
3561 break;
3562 }
3563
3564 g_object_unref (stream);
3565
3566 return ret;
3567 }
3568
3569 static void
3570 rb_player_gst_xfade_pause (RBPlayer *iplayer)
3571 {
3572 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3573 GList *l;
3574 GList *to_fade = NULL;
3575 gboolean done = FALSE;
3576 double fade_out_start = 1.0f;
3577 gint64 fade_out_time = PAUSE_FADE_LENGTH;
3578
3579 g_rec_mutex_lock (&player->priv->stream_list_lock);
3580
3581 for (l = player->priv->streams; l != NULL; l = l->next) {
3582 RBXFadeStream *stream;
3583 stream = (RBXFadeStream *)l->data;
3584 switch (stream->state) {
3585 case WAITING:
3586 case WAITING_EOS:
3587 rb_debug ("stream %s is not yet playing, can't pause", stream->uri);
3588 break;
3589
3590 case PREROLLING:
3591 case PREROLL_PLAY:
3592 rb_debug ("stream %s is prerolling, can't pause", stream->uri);
3593 break;
3594
3595 case REUSING:
3596 rb_debug ("stream %s is being reused, can't pause", stream->uri);
3597 break;
3598
3599 case PAUSED:
3600 case SEEKING_PAUSED:
3601 case FADING_OUT_PAUSED:
3602 rb_debug ("stream %s is already paused", stream->uri);
3603 done = TRUE;
3604 break;
3605
3606 case FADING_IN:
3607 case PLAYING:
3608 rb_debug ("pausing stream %s -> FADING_OUT_PAUSED", stream->uri);
3609 to_fade = g_list_prepend (to_fade, g_object_ref (stream));
3610 done = TRUE;
3611 break;
3612
3613 case SEEKING:
3614 rb_debug ("pausing seeking stream %s -> SEEKING_PAUSED", stream->uri);
3615 stream->state = SEEKING_PAUSED;
3616 done = TRUE;
3617 break;
3618 case SEEKING_EOS:
3619 rb_debug ("stream %s is seeking after EOS -> SEEKING_PAUSED", stream->uri);
3620 stream->state = SEEKING_PAUSED;
3621 done = TRUE;
3622 break;
3623
3624 case FADING_OUT:
3625 rb_debug ("stream %s is fading out, can't be bothered pausing it", stream->uri);
3626 break;
3627
3628 case PENDING_REMOVE:
3629 rb_debug ("stream %s is done, can't pause", stream->uri);
3630 break;
3631 }
3632
3633 if (done)
3634 break;
3635 }
3636
3637 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3638
3639 for (l = to_fade; l != NULL; l = l->next) {
3640 RBXFadeStream *stream = (RBXFadeStream *)l->data;
3641
3642 switch (stream->state) {
3643 case FADING_IN:
3644 g_object_get (stream->volume, "volume", &fade_out_start, NULL);
3645 fade_out_time = (gint64)(((double) PAUSE_FADE_LENGTH) * fade_out_start);
3646
3647 case PLAYING:
3648 stream->state = FADING_OUT_PAUSED;
3649 start_stream_fade (stream, fade_out_start, 0.0f, fade_out_time);
3650
3651 default:
3652 /* shouldn't happen, but ignore it if it does */
3653 break;
3654 }
3655
3656 g_object_unref (stream);
3657 }
3658 g_list_free (to_fade);
3659
3660 if (done == FALSE)
3661 rb_debug ("couldn't find a stream to pause");
3662 }
3663
3664 static gboolean
3665 rb_player_gst_xfade_playing (RBPlayer *iplayer)
3666 {
3667 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3668 gboolean playing = FALSE;
3669 RBXFadeStream *stream;
3670
3671 if (player->priv->sink_state != SINK_PLAYING)
3672 return FALSE;
3673
3674 /* XXX maybe replace with just a flag? */
3675
3676 g_rec_mutex_lock (&player->priv->stream_list_lock);
3677
3678 stream = find_stream_by_state (player, PLAYING | FADING_IN);
3679 if (stream != NULL) {
3680 playing = TRUE;
3681 g_object_unref (stream);
3682 }
3683 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3684 return playing;
3685 }
3686
3687
3688 static void
3689 rb_player_gst_xfade_set_volume (RBPlayer *iplayer, float volume)
3690 {
3691 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3692
3693 player->priv->volume_changed++;
3694 if (player->priv->volume_handler != NULL) {
3695 gdouble v = (gdouble)volume;
3696
3697 /* maybe use a controller here for smoother changes? */
3698 if (gst_element_implements_interface (player->priv->volume_handler,
3699 GST_TYPE_STREAM_VOLUME)) {
3700 gst_stream_volume_set_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
3701 GST_STREAM_VOLUME_FORMAT_CUBIC, v);
3702 } else {
3703 g_object_set (player->priv->volume_handler, "volume", v, NULL);
3704 }
3705 player->priv->volume_applied = player->priv->volume_changed;
3706 }
3707 player->priv->cur_volume = volume;
3708 }
3709
3710
3711 static float
3712 rb_player_gst_xfade_get_volume (RBPlayer *iplayer)
3713 {
3714 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3715
3716 if (gst_element_implements_interface (player->priv->volume_handler, GST_TYPE_STREAM_VOLUME))
3717 return gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
3718 GST_STREAM_VOLUME_FORMAT_CUBIC);
3719
3720 return player->priv->cur_volume;
3721 }
3722
3723 static gboolean
3724 rb_player_gst_xfade_seekable (RBPlayer *iplayer)
3725 {
3726 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3727 gboolean can_seek = TRUE;
3728 RBXFadeStream *stream;
3729
3730 /* is this supposed to query the most recently opened stream,
3731 * or the current playing stream? I really don't know.
3732 */
3733 g_rec_mutex_lock (&player->priv->stream_list_lock);
3734 stream = find_stream_by_state (player, FADING_IN | PAUSED | PLAYING);
3735 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3736
3737 if (stream) {
3738 GstQuery *query = NULL;
3739 query = gst_query_new_seeking (GST_FORMAT_TIME);
3740 if (gst_element_query (stream->volume, query)) {
3741 gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL);
3742 } else {
3743 gst_query_unref (query);
3744
3745 query = gst_query_new_duration (GST_FORMAT_TIME);
3746 can_seek = gst_element_query (stream->volume, query);
3747 }
3748 gst_query_unref (query);
3749 g_object_unref (stream);
3750 }
3751
3752 return can_seek;
3753 }
3754
3755 static void
3756 rb_player_gst_xfade_set_time (RBPlayer *iplayer, gint64 time)
3757 {
3758 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3759 RBXFadeStream *stream;
3760
3761 g_rec_mutex_lock (&player->priv->stream_list_lock);
3762 stream = find_stream_by_state (player, FADING_IN | PLAYING | PAUSED | FADING_OUT_PAUSED | PENDING_REMOVE);
3763 g_rec_mutex_unlock (&player->priv->stream_list_lock);
3764
3765 if (stream == NULL) {
3766 rb_debug ("got seek while no playing streams exist");
3767 return;
3768 }
3769
3770 stream->seek_target = time;
3771 switch (stream->state) {
3772 case PAUSED:
3773 rb_debug ("seeking in paused stream %s; target %"
3774 G_GINT64_FORMAT, stream->uri, stream->seek_target);
3775 perform_seek (stream);
3776 break;
3777
3778 case FADING_OUT_PAUSED:
3779 /* don't unblock and relink when the seek is done */
3780 stream->state = SEEKING_PAUSED;
3781 rb_debug ("seeking in pausing stream %s; target %"
3782 G_GINT64_FORMAT, stream->uri, stream->seek_target);
3783 unlink_and_block_stream (stream);
3784 break;
3785
3786 case FADING_IN:
3787 case PLAYING:
3788 stream->state = SEEKING;
3789 rb_debug ("seeking in playing stream %s; target %"
3790 G_GINT64_FORMAT, stream->uri, stream->seek_target);
3791 perform_seek (stream);
3792 break;
3793
3794 case PENDING_REMOVE:
3795 /* this should only happen when the stream has ended,
3796 * which means we can't wait for the src pad to be blocked
3797 * before we seek. we unlink the stream when it reaches EOS,
3798 * so now we just perform the seek and relink.
3799 */
3800 rb_debug ("seeking in EOS stream %s; target %"
3801 G_GINT64_FORMAT, stream->uri, stream->seek_target);
3802 stream->state = SEEKING_EOS;
3803 gst_pad_set_blocked_async (stream->src_pad,
3804 TRUE,
3805 (GstPadBlockCallback) post_eos_seek_blocked_cb,
3806 stream);
3807 perform_seek (stream);
3808 break;
3809 default:
3810 g_assert_not_reached ();
3811 }
3812
3813 g_object_unref (stream);
3814 }
3815
3816 static gint64
3817 rb_player_gst_xfade_get_time (RBPlayer *iplayer)
3818 {
3819 gint64 pos = -1;
3820 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3821
3822 get_times_and_stream (player, NULL, &pos, NULL);
3823 return pos;
3824 }
3825
3826 static gboolean
3827 need_pad_block (RBPlayerGstXFade *player)
3828 {
3829 return (player->priv->sink_state == SINK_PLAYING);
3830 }
3831
3832 static gboolean
3833 rb_player_gst_xfade_add_tee (RBPlayerGstTee *iplayer, GstElement *element)
3834 {
3835 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3836 if (player->priv->tee == NULL) {
3837 player->priv->waiting_tees = g_list_prepend (player->priv->waiting_tees, element);
3838 return TRUE;
3839 }
3840
3841 return rb_gst_add_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
3842 }
3843
3844 static gboolean
3845 rb_player_gst_xfade_remove_tee (RBPlayerGstTee *iplayer, GstElement *element)
3846 {
3847 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3848 if (player->priv->tee == NULL) {
3849 gst_object_sink (element);
3850 player->priv->waiting_tees = g_list_remove (player->priv->waiting_tees, element);
3851 return TRUE;
3852 }
3853
3854 return rb_gst_remove_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
3855 }
3856
3857
3858 static gboolean
3859 rb_player_gst_xfade_add_filter (RBPlayerGstFilter *iplayer, GstElement *element)
3860 {
3861 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3862 if (player->priv->filterbin == NULL) {
3863 player->priv->waiting_filters = g_list_prepend (player->priv->waiting_filters, element);
3864 return TRUE;
3865 }
3866
3867 return rb_gst_add_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));
3868 }
3869
3870
3871 static gboolean
3872 rb_player_gst_xfade_remove_filter (RBPlayerGstFilter *iplayer, GstElement *element)
3873 {
3874 RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3875 if (player->priv->filterbin == NULL) {
3876 gst_object_sink (element);
3877 player->priv->waiting_filters = g_list_remove (player->priv->waiting_filters, element);
3878 return TRUE;
3879 }
3880
3881 return rb_gst_remove_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));
3882 }