1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2006,2010 Jonathan Matthew <jonathan@d14n.org>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* 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.
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.
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.
30
* GStreamer player backend with crossfading and gaplessness and trees and
31
* flowers and bunnies.
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, decodebin, 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?)
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.
47
* streams go through a number of states:
49
* when a stream is created (in rb_player_open()), it starts in PREROLLING
52
* - rb_player_play(): -> PREROLL_PLAY
53
* - preroll finishes: -> WAITING
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
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
79
* - EOS received for another stream: -> PLAYING, link to adder, unblock
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
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
100
* - rb_player_pause(): -> SEEKING_PAUSED
101
* - blocked: perform seek, link, unblock -> PLAYING | FADING_IN
103
* from SEEKING_PAUSED:
104
* - blocked: perform seek, -> PAUSED
105
* - rb_player_play(): -> SEEKING
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
115
* - fade out finishes: -> PENDING_REMOVE
116
* - EOS: -> PENDING_REMOVE
117
* - reused for another stream: -> REUSING; block, unlink
119
* from FADING_OUT_PAUSED:
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
126
* from PENDING_REMOVE:
127
* - rb_player_set_time(): -> block, seek, -> SEEKING_EOS
128
* - reap_streams idle handler called: -> unlink from adder, stream destroyed
131
* - block completes -> link, unblock, -> PLAYING
132
* - rb_player_pause() -> SEEKING_PAUSED
135
* - EOS: emit reuse-stream, -> PLAYING
136
* - rb_player_play(): -> block, unlink
137
* - blocked: emit reuse-stream, link -> PLAYING
143
#include <glib/gi18n.h>
145
#include <gst/controller/gstinterpolationcontrolsource.h>
146
#include <gst/controller/gstdirectcontrolbinding.h>
147
#include <gst/base/gstbasetransform.h>
148
#include <gst/audio/streamvolume.h>
149
#include <gst/pbutils/pbutils.h>
151
#include "rb-player.h"
152
#include "rb-player-gst-xfade.h"
153
#include "rb-debug.h"
154
#include "rb-file-helpers.h"
156
#include "rb-marshal.h"
157
#include "rb-player-gst-tee.h"
158
#include "rb-player-gst-filter.h"
159
#include "rb-player-gst-helper.h"
161
static void rb_player_init (RBPlayerIface *iface);
162
static void rb_player_gst_tee_init (RBPlayerGstTeeIface *iface);
163
static void rb_player_gst_filter_init (RBPlayerGstFilterIface *iface);
164
static void rb_player_gst_xfade_dispose (GObject *object);
165
static void rb_player_gst_xfade_finalize (GObject *object);
167
static gboolean rb_player_gst_xfade_open (RBPlayer *player,
169
gpointer stream_data,
170
GDestroyNotify stream_data_destroy,
172
static gboolean rb_player_gst_xfade_opened (RBPlayer *player);
173
static gboolean rb_player_gst_xfade_close (RBPlayer *player, const char *uri, GError **error);
174
static gboolean rb_player_gst_xfade_play (RBPlayer *player, RBPlayerPlayType play_type, gint64 crossfade, GError **error);
175
static void rb_player_gst_xfade_pause (RBPlayer *player);
176
static gboolean rb_player_gst_xfade_playing (RBPlayer *player);
177
static gboolean rb_player_gst_xfade_seekable (RBPlayer *player);
178
static void rb_player_gst_xfade_set_time (RBPlayer *player, gint64 time);
179
static gint64 rb_player_gst_xfade_get_time (RBPlayer *player);
180
static void rb_player_gst_xfade_set_volume (RBPlayer *player, float volume);
181
static float rb_player_gst_xfade_get_volume (RBPlayer *player);
182
static gboolean rb_player_gst_xfade_add_tee (RBPlayerGstTee *player, GstElement *element);
183
static gboolean rb_player_gst_xfade_add_filter (RBPlayerGstFilter *player, GstElement *element);
184
static gboolean rb_player_gst_xfade_remove_tee (RBPlayerGstTee *player, GstElement *element);
185
static gboolean rb_player_gst_xfade_remove_filter (RBPlayerGstFilter *player, GstElement *element);
187
static gboolean create_sink (RBPlayerGstXFade *player, GError **error);
188
static gboolean start_sink (RBPlayerGstXFade *player, GError **error);
189
static gboolean stop_sink (RBPlayerGstXFade *player);
190
static void maybe_stop_sink (RBPlayerGstXFade *player);
192
GType rb_xfade_stream_get_type (void);
193
GType rb_xfade_stream_bin_get_type (void);
195
G_DEFINE_TYPE_WITH_CODE(RBPlayerGstXFade, rb_player_gst_xfade, G_TYPE_OBJECT,
196
G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER,
198
G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_TEE,
199
rb_player_gst_tee_init)
200
G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER_GST_FILTER,
201
rb_player_gst_filter_init))
203
#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYER_GST_XFADE, RBPlayerGstXFadePrivate))
205
#define RB_PLAYER_GST_XFADE_TICK_HZ 5
207
#define EPSILON (0.001)
208
#define STREAM_PLAYING_MESSAGE "rb-stream-playing"
209
#define FADE_OUT_DONE_MESSAGE "rb-fade-out-done"
210
#define FADE_IN_DONE_MESSAGE "rb-fade-in-done"
211
#define STREAM_EOS_MESSAGE "rb-stream-eos"
213
#define PAUSE_FADE_LENGTH (GST_SECOND / 2)
231
/* copied from gsturidecodebin.c:stream_uris */
232
static const char *stream_schemes[] = {
233
"http", "https", "mms", "mmsh", "mmsu", "mmst", "ssh", "ftp", "sftp"
236
static guint signals[LAST_SIGNAL] = { 0 };
238
struct _RBPlayerGstXFadePrivate
240
/* probably don't need to store pointers to these either */
241
GstElement *pipeline;
242
GstElement *outputbin;
243
GstElement *silencebin;
245
GstElement *capsfilter;
249
GstElement *filterbin;
250
GstElement *filteridentity;
251
GstElement *filterconvert;
252
GstElement *volume_handler;
261
GList *waiting_filters;
263
GRecMutex stream_list_lock;
271
guint tick_timeout_id;
273
guint stream_reap_id;
279
/* these aren't actually used to construct bitmasks,
280
* but we search the list that way.
289
/* transition states */
295
SEEKING_PAUSED = 256,
299
FADING_OUT_PAUSED = 4096,
300
PENDING_REMOVE = 8192
304
GstBinClass bin_class;
305
} RBXFadeStreamClass;
311
RBPlayerGstXFade *player;
316
gpointer stream_data;
317
GDestroyNotify stream_data_destroy;
319
/* stream reuse data */
321
gpointer new_stream_data;
322
GDestroyNotify new_stream_data_destroy;
324
/* probably don't need to store pointers to all of these.. */
327
GstElement *audioconvert;
328
GstElement *audioresample;
329
GstElement *capsfilter;
331
GstElement *identity;
332
gboolean decoder_linked;
333
gboolean emitted_playing;
334
gboolean emitted_fake_playing;
340
gboolean src_blocked;
341
gboolean needs_unlink;
342
GstClockTime base_time;
346
GstTimedValueControlSource *fader;
348
RBPlayerPlayType play_type;
351
gboolean starting_eos;
352
gboolean use_buffering;
354
gulong adjust_probe_id;
355
gulong block_probe_id;
359
gboolean emitted_error;
360
gulong error_idle_id;
363
GSList *missing_plugins;
364
gulong emit_missing_plugins_id;
369
#define RB_TYPE_XFADE_STREAM (rb_xfade_stream_get_type ())
370
#define RB_XFADE_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_XFADE_STREAM, RBXFadeStream))
371
#define RB_IS_XFADE_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_XFADE_STREAM))
373
static void adjust_stream_base_time (RBXFadeStream *stream);
374
static gboolean actually_start_stream (RBXFadeStream *stream, GError **error);
376
static void rb_xfade_stream_class_init (RBXFadeStreamClass *klass);
378
G_DEFINE_TYPE(RBXFadeStream, rb_xfade_stream, GST_TYPE_BIN)
381
rb_xfade_stream_send_event (GstElement *element, GstEvent *event)
387
/* just send the event to the element that provides the src pad */
388
ghost_pad = gst_element_get_static_pad (element, "src");
389
pad = gst_ghost_pad_get_target (GST_GHOST_PAD (ghost_pad));
391
ret = gst_element_send_event (GST_PAD_PARENT (pad), event);
393
gst_object_unref (pad);
394
gst_object_unref (ghost_pad);
400
rb_xfade_stream_init (RBXFadeStream *stream)
402
g_mutex_init (&stream->lock);
406
rb_xfade_stream_dispose_stream_data (RBXFadeStream *stream)
408
if (stream->stream_data && stream->stream_data_destroy) {
409
stream->stream_data_destroy (stream->stream_data);
411
stream->stream_data = NULL;
412
stream->stream_data_destroy = NULL;
416
rb_xfade_stream_dispose (GObject *object)
418
RBXFadeStream *sd = RB_XFADE_STREAM (object);
420
rb_debug ("disposing stream %s", sd->uri);
422
if (sd->decoder != NULL) {
423
gst_object_unref (sd->decoder);
427
if (sd->volume != NULL) {
428
gst_object_unref (sd->volume);
432
if (sd->fader != NULL) {
433
gst_object_unref (sd->fader);
437
if (sd->audioconvert != NULL) {
438
gst_object_unref (sd->audioconvert);
439
sd->audioconvert = NULL;
442
if (sd->audioresample != NULL) {
443
gst_object_unref (sd->audioresample);
444
sd->audioresample = NULL;
447
if (sd->player != NULL) {
448
g_object_unref (sd->player);
452
if (sd->tags != NULL) {
453
rb_list_destroy_free (sd->tags, (GDestroyNotify) gst_tag_list_unref);
457
rb_xfade_stream_dispose_stream_data (sd);
459
G_OBJECT_CLASS (rb_xfade_stream_parent_class)->dispose (object);
463
rb_xfade_stream_finalize (GObject *object)
465
RBXFadeStream *sd = RB_XFADE_STREAM (object);
469
if (sd->error != NULL) {
470
g_error_free (sd->error);
473
G_OBJECT_CLASS (rb_xfade_stream_parent_class)->finalize (object);
477
rb_xfade_stream_class_init (RBXFadeStreamClass *klass)
479
GObjectClass *object_class = G_OBJECT_CLASS (klass);
480
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
482
object_class->dispose = rb_xfade_stream_dispose;
483
object_class->finalize = rb_xfade_stream_finalize;
485
element_class->send_event = rb_xfade_stream_send_event;
488
/* caller must hold stream list lock */
490
dump_stream_list (RBPlayerGstXFade *player)
493
if (player->priv->streams == NULL) {
494
rb_debug ("stream list is empty");
496
rb_debug ("current stream list:");
497
for (l = player->priv->streams; l != NULL; l = l->next) {
498
RBXFadeStream *stream = (RBXFadeStream *)l->data;
499
const char *statename = "<wtf>";
500
switch (stream->state) {
501
case WAITING: statename = "waiting"; break;
502
case PLAYING: statename = "playing"; break;
503
case PAUSED: statename = "paused"; break;
505
case REUSING: statename = "reusing"; break;
506
case PREROLLING: statename = "prerolling"; break;
507
case PREROLL_PLAY: statename = "preroll->play"; break;
508
case FADING_IN: statename = "fading in"; break;
509
case SEEKING: statename = "seeking"; break;
510
case SEEKING_PAUSED: statename = "seeking->paused"; break;
511
case SEEKING_EOS: statename = "seeking post EOS"; break;
512
case WAITING_EOS: statename = "waiting for EOS"; break;
513
case FADING_OUT: statename = "fading out"; break;
514
case FADING_OUT_PAUSED: statename = "fading->paused"; break;
516
case PENDING_REMOVE: statename = "pending remove"; break;
519
rb_debug ("[%s] %s", statename, stream->uri);
524
/* caller must hold stream list lock */
525
static RBXFadeStream *
526
find_stream_by_uri (RBPlayerGstXFade *player, const char *uri)
532
for (i = player->priv->streams; i != NULL; i = i->next) {
533
RBXFadeStream *stream = (RBXFadeStream *)i->data;
534
if (strcmp (uri, stream->uri) == 0)
535
return g_object_ref (stream);
540
/* caller must hold stream list lock */
541
static RBXFadeStream *
542
find_stream_by_element (RBPlayerGstXFade *player, GstElement *element)
546
for (i = player->priv->streams; i != NULL; i = i->next) {
547
RBXFadeStream *stream;
550
stream = (RBXFadeStream *)i->data;
553
if (e == GST_ELEMENT (stream))
554
return g_object_ref (stream);
556
e = GST_ELEMENT_PARENT (e);
563
/* caller must hold stream list lock */
564
static RBXFadeStream *
565
find_stream_by_state (RBPlayerGstXFade *player, gint state_mask)
569
for (i = player->priv->streams; i != NULL; i = i->next) {
570
RBXFadeStream *stream;
572
stream = (RBXFadeStream *)i->data;
573
if ((stream->state & state_mask) != 0) {
574
return g_object_ref (stream);
581
static RBXFadeStream *
582
find_stream_for_message (RBPlayerGstXFade *player, GstMessage *message)
584
GstObject *message_src;
585
RBXFadeStream *stream;
587
/* first see if the message comes from an element in the stream bin */
588
message_src = GST_MESSAGE_SRC (message);
589
if (GST_IS_PAD (message_src)) {
590
message_src = GST_OBJECT_PARENT (message_src);
592
stream = find_stream_by_element (player, GST_ELEMENT (message_src));
596
/* tag messages are emitted by the sink, so we can't find the message
597
* source in a stream bin. attribute them to the first playing stream.
599
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TAG) {
600
return find_stream_by_state (player, FADING_IN | PLAYING | FADING_OUT_PAUSED | PAUSED | PENDING_REMOVE | REUSING);
607
rb_player_gst_xfade_get_property (GObject *object,
612
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);
616
if (player->priv->pipeline) {
618
bus = gst_element_get_bus (player->priv->pipeline);
619
g_value_set_object (value, bus);
620
gst_object_unref (bus);
624
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
630
rb_player_gst_xfade_set_property (GObject *object,
635
/*RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);*/
639
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645
rb_player_gst_xfade_class_init (RBPlayerGstXFadeClass *klass)
647
GObjectClass *object_class = G_OBJECT_CLASS (klass);
649
object_class->dispose = rb_player_gst_xfade_dispose;
650
object_class->finalize = rb_player_gst_xfade_finalize;
651
object_class->set_property = rb_player_gst_xfade_set_property;
652
object_class->get_property = rb_player_gst_xfade_get_property;
654
g_object_class_install_property (object_class,
656
g_param_spec_object ("bus",
658
"GStreamer message bus",
662
signals[PREPARE_SOURCE] =
663
g_signal_new ("prepare-source",
664
G_OBJECT_CLASS_TYPE (object_class),
666
G_STRUCT_OFFSET (RBPlayerGstXFadeClass, prepare_source),
668
rb_marshal_VOID__STRING_OBJECT,
671
G_TYPE_STRING, GST_TYPE_ELEMENT);
672
signals[CAN_REUSE_STREAM] =
673
g_signal_new ("can-reuse-stream",
674
G_OBJECT_CLASS_TYPE (object_class),
676
G_STRUCT_OFFSET (RBPlayerGstXFadeClass, can_reuse_stream),
678
rb_marshal_BOOLEAN__STRING_STRING_OBJECT,
681
G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
682
signals[REUSE_STREAM] =
683
g_signal_new ("reuse-stream",
684
G_OBJECT_CLASS_TYPE (object_class),
686
G_STRUCT_OFFSET (RBPlayerGstXFadeClass, reuse_stream),
688
rb_marshal_VOID__STRING_STRING_OBJECT,
691
G_TYPE_STRING, G_TYPE_STRING, GST_TYPE_ELEMENT);
692
signals[MISSING_PLUGINS] =
693
g_signal_new ("missing-plugins",
694
G_OBJECT_CLASS_TYPE (object_class),
696
0, /* no point handling this internally */
698
rb_marshal_VOID__POINTER_POINTER_POINTER,
701
G_TYPE_POINTER, G_TYPE_STRV, G_TYPE_STRV);
702
signals[GET_STREAM_FILTERS] =
703
g_signal_new ("get-stream-filters",
704
G_OBJECT_CLASS_TYPE (object_class),
707
rb_signal_accumulator_value_array, NULL,
708
rb_marshal_BOXED__STRING,
713
g_type_class_add_private (klass, sizeof (RBPlayerGstXFadePrivate));
717
rb_player_init (RBPlayerIface *iface)
719
iface->open = rb_player_gst_xfade_open;
720
iface->opened = rb_player_gst_xfade_opened;
721
iface->close = rb_player_gst_xfade_close;
722
iface->play = rb_player_gst_xfade_play;
723
iface->pause = rb_player_gst_xfade_pause;
724
iface->playing = rb_player_gst_xfade_playing;
725
iface->set_volume = rb_player_gst_xfade_set_volume;
726
iface->get_volume = rb_player_gst_xfade_get_volume;
727
iface->seekable = rb_player_gst_xfade_seekable;
728
iface->set_time = rb_player_gst_xfade_set_time;
729
iface->get_time = rb_player_gst_xfade_get_time;
730
iface->multiple_open = (RBPlayerFeatureFunc) rb_true_function;
734
rb_player_gst_tee_init (RBPlayerGstTeeIface *iface)
736
iface->add_tee = rb_player_gst_xfade_add_tee;
737
iface->remove_tee = rb_player_gst_xfade_remove_tee;
741
rb_player_gst_filter_init (RBPlayerGstFilterIface *iface)
743
iface->add_filter = rb_player_gst_xfade_add_filter;
744
iface->remove_filter = rb_player_gst_xfade_remove_filter;
749
rb_player_gst_xfade_init (RBPlayerGstXFade *player)
751
player->priv = GET_PRIVATE (player);
753
g_rec_mutex_init (&player->priv->stream_list_lock);
754
g_rec_mutex_init (&player->priv->sink_lock);
755
player->priv->cur_volume = 1.0f;
759
rb_player_gst_xfade_dispose (GObject *object)
761
RBPlayerGstXFade *player;
764
g_return_if_fail (RB_IS_PLAYER_GST_XFADE (object));
765
player = RB_PLAYER_GST_XFADE (object);
767
/* clean up streams */
768
g_rec_mutex_lock (&player->priv->stream_list_lock);
769
for (l = player->priv->streams; l != NULL; l = l->next) {
770
RBXFadeStream *stream = (RBXFadeStream *)l->data;
772
/* unlink instead? */
773
gst_element_set_state (GST_ELEMENT (stream), GST_STATE_NULL);
775
g_object_unref (stream);
777
g_list_free (player->priv->streams);
778
player->priv->streams = NULL;
779
g_rec_mutex_unlock (&player->priv->stream_list_lock);
781
if (player->priv->volume_handler) {
782
g_object_unref (player->priv->volume_handler);
783
player->priv->volume_handler = NULL;
786
g_rec_mutex_lock (&player->priv->sink_lock);
788
g_rec_mutex_unlock (&player->priv->sink_lock);
790
if (player->priv->pipeline != NULL) {
791
/* maybe we should keep references to the adder, sink, etc.? */
792
gst_element_set_state (player->priv->pipeline, GST_STATE_NULL);
793
g_object_unref (player->priv->pipeline);
794
player->priv->pipeline = NULL;
797
G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->dispose (object);
801
rb_player_gst_xfade_finalize (GObject *object)
803
RBPlayerGstXFade *player;
805
player = RB_PLAYER_GST_XFADE (object);
807
if (player->priv->waiting_tees) {
808
g_list_foreach (player->priv->waiting_tees, (GFunc)gst_object_ref_sink, NULL);
810
g_list_free (player->priv->waiting_tees);
812
if (player->priv->waiting_filters) {
813
g_list_foreach (player->priv->waiting_filters, (GFunc)gst_object_ref_sink, NULL);
815
g_list_free (player->priv->waiting_filters);
817
G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->finalize (object);
821
rb_player_gst_xfade_new (GError **error)
825
mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER_GST_XFADE, NULL, NULL));
831
emit_stream_error_cb (RBXFadeStream *stream)
833
stream->error_idle_id = 0;
834
_rb_player_emit_error (RB_PLAYER (stream->player),
837
g_error_free (stream->error);
838
stream->error = NULL;
844
emit_stream_error (RBXFadeStream *stream, GError *error)
846
if (stream->error_idle_id != 0) {
847
g_error_free (error);
849
stream->error = error;
850
stream->error_idle_id = g_idle_add ((GSourceFunc) emit_stream_error_cb,
856
post_stream_playing_message (RBXFadeStream *stream, gboolean fake)
861
if (stream->emitted_playing) {
865
rb_debug ("posting " STREAM_PLAYING_MESSAGE " message for stream %s", stream->uri);
866
s = gst_structure_new_empty (STREAM_PLAYING_MESSAGE);
867
msg = gst_message_new_application (GST_OBJECT (stream), s);
868
gst_element_post_message (GST_ELEMENT (stream), msg);
871
stream->emitted_playing = TRUE;
873
stream->emitted_fake_playing = TRUE;
877
static GstPadProbeReturn
878
adjust_base_time_probe_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
880
rb_debug ("attempting to adjust base time for stream %s", stream->uri);
881
g_mutex_lock (&stream->lock);
882
adjust_stream_base_time (stream);
883
g_mutex_unlock (&stream->lock);
884
return GST_PAD_PROBE_OK;
887
/* updates a stream's base time so its position is reported correctly */
889
adjust_stream_base_time (RBXFadeStream *stream)
891
gint64 output_pos = -1;
892
gint64 stream_pos = -1;
894
if (stream->adder_pad == NULL) {
895
rb_debug ("stream isn't linked, can't adjust base time");
899
gst_element_query_position (GST_PAD_PARENT (stream->adder_pad), GST_FORMAT_TIME, &output_pos);
900
if (output_pos != -1) {
901
stream->base_time = output_pos;
904
/* offset the base position to account for the current stream position */
905
gst_element_query_position (stream->volume, GST_FORMAT_TIME, &stream_pos);
906
if (stream_pos != -1) {
907
rb_debug ("adjusting base time: %" G_GINT64_FORMAT
908
" - %" G_GINT64_FORMAT " => %" G_GINT64_FORMAT,
909
stream->base_time, stream_pos,
910
stream->base_time - stream_pos);
911
stream->base_time -= stream_pos;
913
/* once we've successfully adjusted the base time, we don't need the data probe */
914
if (stream->adjust_probe_id != 0) {
915
gst_pad_remove_probe (stream->ghost_pad, stream->adjust_probe_id);
916
stream->adjust_probe_id = 0;
919
rb_debug ("unable to adjust base time as position query failed");
921
/* add a pad probe to attempt to adjust when the next buffer goes out */
922
if (stream->adjust_probe_id == 0) {
923
stream->adjust_probe_id =
924
gst_pad_add_probe (stream->ghost_pad,
925
GST_PAD_PROBE_TYPE_BUFFER,
926
(GstPadProbeCallback) adjust_base_time_probe_cb,
933
/* called on a streaming thread when the volume level for a stream changes. */
935
volume_changed_cb (GObject *object, GParamSpec *pspec, RBPlayerGstXFade *player)
937
RBXFadeStream *stream;
939
char *message = NULL;
941
/* post app messages on the bus when fades complete.
942
* our bus callback will handle them on the main thread.
945
g_rec_mutex_lock (&player->priv->stream_list_lock);
946
stream = find_stream_by_element (player, GST_ELEMENT (object));
947
g_rec_mutex_unlock (&player->priv->stream_list_lock);
949
if (stream == NULL) {
950
rb_debug ("got volume change for unknown stream");
954
g_mutex_lock (&stream->lock);
956
/* check if the fade is complete */
957
g_object_get (stream->volume, "volume", &vol, NULL);
958
switch (stream->state) {
960
if (vol > (stream->fade_end - EPSILON) && stream->fading) {
961
rb_debug ("stream %s fully faded in (at %f) -> PLAYING state", stream->uri, vol);
962
message = FADE_IN_DONE_MESSAGE;
963
stream->fading = FALSE;
964
stream->state = PLAYING;
967
rb_debug ("fading %s in: %f", stream->uri, (float)vol);*/
971
case FADING_OUT_PAUSED:
972
if (vol < (stream->fade_end + EPSILON)) {
973
rb_debug ("stream %s fully faded out (at %f)", stream->uri, vol);
974
if (stream->fading) {
975
message = FADE_OUT_DONE_MESSAGE;
976
stream->fading = FALSE;
979
/*rb_debug ("fading %s out: %f", stream->uri, (float)vol);*/
980
/* force the volume element out of passthrough mode so it
981
* continues to update the controller (otherwise, if the
982
* fade out starts at 1.0, it never gets anywhere)
984
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
988
/*rb_debug ("unexpectedly got a volume change for stream %s to %f (not fading)", stream->uri, (float)vol);*/
992
g_mutex_unlock (&stream->lock);
994
if (message != NULL) {
998
rb_debug ("posting %s message for stream %s", message, stream->uri);
999
s = gst_structure_new_empty (message);
1000
msg = gst_message_new_application (GST_OBJECT (object), s);
1001
gst_element_post_message (GST_ELEMENT (object), msg);
1004
g_object_unref (stream);
1007
/* starts a volume slide on a stream.
1008
* volume_changed_cb watches the volume change
1009
* and posts a message on the bus when the slide
1013
start_stream_fade (RBXFadeStream *stream, double start, double end, gint64 time)
1017
/* hmm, can we take the stream lock safely here? probably should.. */
1019
gst_element_query_position (stream->volume, GST_FORMAT_TIME, &pos);
1021
/* probably means we haven't actually started the stream yet.
1022
* we also get (weird) negative results with some decoders
1023
* (mad but not flump3dec, for instance) immediately after prerolling.
1024
* the controller doesn't seem to work if we give it a 0 timestamp
1025
* here, but something unnoticeably later does work.
1030
rb_debug ("fading stream %s: [%f, %" G_GINT64_FORMAT "] to [%f, %" G_GINT64_FORMAT "]",
1033
(float)end, pos + time);
1035
g_signal_handlers_block_by_func (stream->volume, volume_changed_cb, stream->player);
1037
/* apparently we need to set the starting volume, otherwise fading in doesn't work. */
1038
stream->fade_end = end;
1039
g_object_set (stream->volume, "volume", start, NULL);
1041
gst_timed_value_control_source_unset_all (stream->fader);
1043
if (gst_timed_value_control_source_set (stream->fader, pos, start/10.0) == FALSE) {
1044
rb_debug ("controller didn't like our start point");
1046
if (gst_timed_value_control_source_set (stream->fader, 0, start/10.0) == FALSE) {
1047
rb_debug ("controller didn't like our 0 start point");
1050
if (gst_timed_value_control_source_set (stream->fader, pos + time, end/10.0) == FALSE) {
1051
rb_debug ("controller didn't like our end point");
1054
g_signal_handlers_unblock_by_func (stream->volume, volume_changed_cb, stream->player);
1056
stream->fading = TRUE;
1058
/* tiny hack: if the controlled element is in passthrough mode, the
1059
* controller won't get updated.
1061
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
1065
/* links a stream bin to the adder
1066
* - adds the bin to the pipeline
1067
* - links to a new adder pad
1068
* - unblocks the stream if it's blocked
1071
link_and_unblock_stream (RBXFadeStream *stream, GError **error)
1073
GstPadLinkReturn plr;
1074
GstStateChangeReturn scr;
1075
RBPlayerGstXFade *player = stream->player;
1078
if (start_sink (player, error) == FALSE) {
1079
rb_debug ("sink didn't start, so we're not going to link the stream");
1083
if (stream->adder_pad != NULL) {
1084
rb_debug ("stream %s is already linked", stream->uri);
1087
stream->needs_unlink = FALSE;
1089
rb_debug ("linking stream %s", stream->uri);
1090
if (GST_ELEMENT_PARENT (GST_ELEMENT (stream)) == NULL)
1091
gst_bin_add (GST_BIN (player->priv->pipeline), GST_ELEMENT (stream));
1093
stream->adder_pad = gst_element_get_request_pad (player->priv->adder, "sink_%u");
1094
if (stream->adder_pad == NULL) {
1095
/* this error message kind of sucks */
1096
rb_debug ("couldn't get adder pad to link in new stream");
1099
RB_PLAYER_ERROR_GENERAL,
1100
_("Failed to link new stream into GStreamer pipeline"));
1104
plr = gst_pad_link (stream->ghost_pad, stream->adder_pad);
1105
if (GST_PAD_LINK_FAILED (plr)) {
1106
gst_element_release_request_pad (player->priv->adder, stream->adder_pad);
1107
stream->adder_pad = NULL;
1109
/* this error message kind of sucks */
1110
rb_debug ("linking stream pad to adder pad failed: %d", plr);
1113
RB_PLAYER_ERROR_GENERAL,
1114
_("Failed to link new stream into GStreamer pipeline"));
1119
g_atomic_int_inc (&player->priv->linked_streams);
1120
rb_debug ("now have %d linked streams", player->priv->linked_streams);
1123
g_mutex_lock (&stream->lock);
1124
if (stream->src_blocked) {
1125
GstStateChangeReturn state_ret;
1127
gst_pad_remove_probe (stream->src_pad, stream->block_probe_id);
1128
stream->block_probe_id = 0;
1130
rb_debug ("stream %s is unblocked -> FADING_IN | PLAYING", stream->uri);
1131
stream->src_blocked = FALSE;
1133
stream->state = FADING_IN;
1135
stream->state = PLAYING;
1137
adjust_stream_base_time (stream);
1139
/* should handle state change failures here.. */
1140
state_ret = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
1141
rb_debug ("stream %s state change returned: %s", stream->uri,
1142
gst_element_state_change_return_get_name (state_ret));
1144
post_stream_playing_message (stream, FALSE);
1146
rb_debug ("??? stream %s is already unblocked -> PLAYING", stream->uri);
1147
stream->state = PLAYING;
1148
adjust_stream_base_time (stream);
1150
scr = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
1152
post_stream_playing_message (stream, FALSE);
1154
if (scr == GST_STATE_CHANGE_FAILURE) {
1157
RB_PLAYER_ERROR_GENERAL,
1158
_("Failed to start new stream"));
1162
g_mutex_unlock (&stream->lock);
1167
* reuses a stream. the stream reuse signal is handled by some
1168
* external code somewhere.
1171
reuse_stream (RBXFadeStream *stream)
1173
g_signal_emit (stream->player,
1174
signals[REUSE_STREAM], 0,
1175
stream->new_uri, stream->uri, GST_ELEMENT (stream));
1177
/* replace URI and stream data */
1178
g_free (stream->uri);
1179
stream->uri = stream->new_uri;
1181
rb_xfade_stream_dispose_stream_data (stream);
1182
stream->stream_data = stream->new_stream_data;
1183
stream->stream_data_destroy = stream->new_stream_data_destroy;
1185
stream->new_uri = NULL;
1186
stream->new_stream_data = NULL;
1187
stream->new_stream_data_destroy = NULL;
1189
stream->emitted_playing = FALSE;
1194
* performs a seek on an unlinked and blocked stream.
1195
* if the stream is still in FADING_IN or PLAYING state,
1196
* relinks and unblocks the stream.
1199
perform_seek (RBXFadeStream *stream)
1203
rb_debug ("sending seek event..");
1205
event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
1206
GST_SEEK_FLAG_FLUSH,
1207
GST_SEEK_TYPE_SET, stream->seek_target,
1208
GST_SEEK_TYPE_NONE, -1);
1209
gst_pad_send_event (stream->src_pad, event);
1211
g_mutex_lock (&stream->lock);
1212
switch (stream->state) {
1214
stream->state = PLAYING;
1216
case SEEKING_PAUSED:
1217
rb_debug ("leaving paused stream %s unlinked", stream->uri);
1218
stream->state = PAUSED;
1221
rb_debug ("waiting for pad block to complete for %s before unlinking", stream->uri);
1227
g_mutex_unlock (&stream->lock);
1231
perform_seek_idle (RBXFadeStream *stream)
1233
perform_seek (stream);
1234
g_object_unref (stream);
1239
* called when a stream doing a post-EOS seek is blocked. this indicates
1240
* that the seek has completed (that's the only way data can flow out of
1241
* the stream bin), so the stream can be linked and unblocked.
1243
static GstPadProbeReturn
1244
post_eos_seek_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
1246
GError *error = NULL;
1248
g_mutex_lock (&stream->lock);
1249
rb_debug ("stream %s is blocked; linking and unblocking", stream->uri);
1250
stream->src_blocked = TRUE;
1251
g_mutex_unlock (&stream->lock);
1253
if (link_and_unblock_stream (stream, &error) == FALSE) {
1254
emit_stream_error (stream, error);
1258
return GST_PAD_PROBE_REMOVE;
1262
* called when a src pad for a stream is blocked during reuse.
1263
* we don't need to do anything here.
1265
static GstPadProbeReturn
1266
unlink_reuse_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
1268
return GST_PAD_PROBE_OK;
1272
unlink_reuse_relink (RBPlayerGstXFade *player, RBXFadeStream *stream)
1274
GError *error = NULL;
1276
g_mutex_lock (&stream->lock);
1278
if (stream->adder_pad == NULL) {
1279
rb_debug ("stream %s doesn't need to be unlinked.. weird.", stream->uri);
1281
rb_debug ("unlinking stream %s for reuse", stream->uri);
1283
if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1284
g_warning ("Couldn't unlink stream %s: this is going to suck.", stream->uri);
1287
gst_element_release_request_pad (player->priv->adder, stream->adder_pad);
1288
stream->adder_pad = NULL;
1290
(void) g_atomic_int_dec_and_test (&player->priv->linked_streams);
1291
rb_debug ("%d linked streams left", player->priv->linked_streams);
1294
stream->needs_unlink = FALSE;
1295
stream->emitted_playing = FALSE;
1297
g_mutex_unlock (&stream->lock);
1299
/* block the src pad so we don't get not-linked errors if it pushes a buffer
1300
* before we get around to relinking
1302
gst_pad_add_probe (stream->src_pad,
1303
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1304
(GstPadProbeCallback) unlink_reuse_blocked_cb,
1307
stream->src_blocked = TRUE;
1309
reuse_stream (stream);
1310
if (link_and_unblock_stream (stream, &error) == FALSE) {
1311
emit_stream_error (stream, error);
1315
/* called when a stream's source pad is blocked, so it can be unlinked
1316
* from the pipeline.
1318
static GstPadProbeReturn
1319
unlink_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
1323
RBPlayerGstXFade *player;
1324
GError *error = NULL;
1326
g_mutex_lock (&stream->lock);
1328
if (stream->needs_unlink == FALSE || stream->adder_pad == NULL) {
1329
g_mutex_unlock (&stream->lock);
1330
return GST_PAD_PROBE_OK;
1333
rb_debug ("stream %s is blocked; unlinking", stream->uri);
1335
if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1336
g_warning ("Couldn't unlink stream %s: things will probably go quite badly from here on", stream->uri);
1338
stream->needs_unlink = FALSE;
1340
gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
1341
stream->adder_pad = NULL;
1343
stream->src_blocked = TRUE;
1344
stream->emitted_playing = FALSE;
1346
stream_state = stream->state;
1347
player = stream->player;
1349
g_mutex_unlock (&stream->lock);
1351
/* might want a stream-paused signal here? */
1353
last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
1354
rb_debug ("%d linked streams left", player->priv->linked_streams);
1356
/* handle unlinks for seeking and stream reuse */
1357
switch (stream_state) {
1359
reuse_stream (stream);
1360
if (link_and_unblock_stream (stream, &error) == FALSE) {
1361
emit_stream_error (stream, error);
1365
case SEEKING_PAUSED:
1366
g_idle_add ((GSourceFunc) perform_seek_idle, g_object_ref (stream));
1367
/* fall through. this only happens when pausing, so it's OK
1368
* to stop the sink here.
1371
/* consider pausing the sink if this is the linked last stream */
1373
maybe_stop_sink (player);
1379
return GST_PAD_PROBE_OK;
1383
* blocks and unlinks a stream. this is the only way we can pause a stream -
1384
* if the stream is linked to the adder and the audio sink is in PLAYING, the
1388
unlink_and_block_stream (RBXFadeStream *stream)
1390
g_mutex_lock (&stream->lock);
1391
if (stream->adder_pad == NULL) {
1392
rb_debug ("stream %s is not linked", stream->uri);
1393
g_mutex_unlock (&stream->lock);
1397
stream->needs_unlink = TRUE;
1398
if (stream->src_blocked) {
1399
/* probably shouldn't happen, but we'll handle it anyway */
1400
g_mutex_unlock (&stream->lock);
1401
unlink_blocked_cb (stream->src_pad, NULL, stream);
1405
if (stream->block_probe_id == 0) {
1406
stream->block_probe_id = gst_pad_add_probe (stream->src_pad,
1407
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1408
(GstPadProbeCallback) unlink_blocked_cb,
1412
rb_debug ("already unlinking");
1414
g_mutex_unlock (&stream->lock);
1418
* sets a stream to NULL state, unlinks it from the adder,
1419
* removes it from the pipeline, removes it from the
1420
* stream list, and frees it (hopefully).
1422
* must not be called on a streaming thread.
1425
unlink_and_dispose_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
1427
GstStateChangeReturn sr;
1428
gboolean was_linked = FALSE;
1429
gboolean was_in_pipeline = FALSE;
1431
/* seems to be too much locking in here.. */
1434
rb_debug ("stopping stream %s", stream->uri);
1435
sr = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_NULL);
1436
if (sr == GST_STATE_CHANGE_ASYNC) {
1437
/* downward state transitions aren't supposed to return ASYNC.. */
1438
rb_debug ("!!! stream %s isn't cooperating", stream->uri);
1439
gst_element_get_state (GST_ELEMENT (stream), NULL, NULL, GST_CLOCK_TIME_NONE);
1442
g_mutex_lock (&stream->lock);
1444
if (stream->adder_pad != NULL) {
1445
rb_debug ("unlinking stream %s", stream->uri);
1446
if (gst_pad_unlink (stream->ghost_pad, stream->adder_pad) == FALSE) {
1447
g_warning ("Couldn't unlink stream %s: things will probably go quite badly from here on", stream->uri);
1450
gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
1451
stream->adder_pad = NULL;
1456
was_in_pipeline = (GST_ELEMENT_PARENT (GST_ELEMENT (stream)) == player->priv->pipeline);
1458
g_mutex_unlock (&stream->lock);
1460
if (was_in_pipeline)
1461
gst_bin_remove (GST_BIN (player->priv->pipeline), GST_ELEMENT (stream));
1466
last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
1467
rb_debug ("now have %d linked streams", player->priv->linked_streams);
1470
maybe_stop_sink (player);
1474
g_rec_mutex_lock (&player->priv->stream_list_lock);
1475
player->priv->streams = g_list_remove (player->priv->streams, stream);
1476
dump_stream_list (player);
1477
g_rec_mutex_unlock (&player->priv->stream_list_lock);
1479
g_object_unref (stream);
1482
/* idle handler used to clean up finished streams */
1484
reap_streams (RBPlayerGstXFade *player)
1489
g_rec_mutex_lock (&player->priv->stream_list_lock);
1490
player->priv->stream_reap_id = 0;
1491
dump_stream_list (player);
1492
for (t = player->priv->streams; t != NULL; t = t->next) {
1493
RBXFadeStream *stream = (RBXFadeStream *)t->data;
1495
if (stream->state == PENDING_REMOVE) {
1496
reap = g_list_prepend (reap, stream);
1499
g_rec_mutex_unlock (&player->priv->stream_list_lock);
1501
for (t = reap; t != NULL; t = t->next) {
1502
RBXFadeStream *stream = (RBXFadeStream *)t->data;
1503
rb_debug ("reaping stream %s", stream->uri);
1504
unlink_and_dispose_stream (player, stream);
1511
/* schedules a call to reap_streams */
1513
schedule_stream_reap (RBPlayerGstXFade *player)
1515
g_rec_mutex_lock (&player->priv->stream_list_lock);
1517
if (player->priv->stream_reap_id == 0) {
1518
dump_stream_list (player);
1519
player->priv->stream_reap_id = g_idle_add ((GSourceFunc) reap_streams, player);
1522
g_rec_mutex_unlock (&player->priv->stream_list_lock);
1525
/* emits a tag signal from the player, maybe */
1527
process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
1529
RBMetaDataField field;
1530
GValue value = {0,};
1532
/* process embedded images */
1533
if (!g_strcmp0 (tag, GST_TAG_IMAGE) || !g_strcmp0 (tag, GST_TAG_PREVIEW_IMAGE)) {
1535
pixbuf = rb_gst_process_embedded_image (list, tag);
1536
if (pixbuf != NULL) {
1537
_rb_player_emit_image (RB_PLAYER (stream->player),
1538
stream->stream_data,
1540
g_object_unref (pixbuf);
1542
} else if (rb_gst_process_tag_string (list, tag, &field, &value)) {
1543
rb_debug ("emitting info field %d", field);
1544
_rb_player_emit_info (RB_PLAYER (stream->player),
1545
stream->stream_data,
1548
g_value_unset (&value);
1554
emit_missing_plugins (RBXFadeStream *stream)
1557
char **descriptions;
1562
stream->emit_missing_plugins_id = 0;
1563
count = g_slist_length (stream->missing_plugins);
1565
details = g_new0 (char *, count + 1);
1566
descriptions = g_new0 (char *, count + 1);
1568
for (t = stream->missing_plugins; t != NULL; t = t->next) {
1569
GstMessage *msg = GST_MESSAGE (t->data);
1573
detail = gst_missing_plugin_message_get_installer_detail (msg);
1574
description = gst_missing_plugin_message_get_description (msg);
1575
details[i] = g_strdup (detail);
1576
descriptions[i] = g_strdup (description);
1579
gst_message_unref (msg);
1582
g_signal_emit (stream->player, signals[MISSING_PLUGINS], 0, stream->stream_data, details, descriptions);
1583
g_strfreev (details);
1584
g_strfreev (descriptions);
1586
g_slist_free (stream->missing_plugins);
1587
stream->missing_plugins = NULL;
1594
rb_player_gst_xfade_handle_missing_plugin_message (RBPlayerGstXFade *player, RBXFadeStream *stream, GstMessage *message)
1596
if (stream == NULL) {
1597
rb_debug ("got missing-plugin message from unknown stream");
1601
rb_debug ("got missing-plugin message from %s: %s",
1603
gst_missing_plugin_message_get_installer_detail (message));
1605
/* can only handle missing-plugins while prerolling */
1606
switch (stream->state) {
1609
stream->missing_plugins = g_slist_prepend (stream->missing_plugins,
1610
gst_message_ref (message));
1611
if (stream->emit_missing_plugins_id == 0) {
1612
stream->emit_missing_plugins_id =
1613
g_idle_add ((GSourceFunc) emit_missing_plugins,
1614
g_object_ref (stream));
1617
/* what do we do now? if we're missing the decoder
1618
* or something, it'll never preroll..
1623
rb_debug ("can't process missing-plugin messages for this stream now");
1629
start_waiting_eos_streams (RBPlayerGstXFade *player)
1632
GList *to_start = NULL;
1634
g_rec_mutex_lock (&player->priv->stream_list_lock);
1635
for (l = player->priv->streams; l != NULL; l = l->next) {
1636
RBXFadeStream *pstream = l->data;
1637
if (pstream->state == WAITING_EOS && pstream->starting_eos == FALSE) {
1638
pstream->starting_eos = TRUE;
1639
to_start = g_list_prepend (to_start, g_object_ref (pstream));
1642
g_rec_mutex_unlock (&player->priv->stream_list_lock);
1644
for (l = to_start; l != NULL; l = l->next) {
1645
RBXFadeStream *pstream = l->data;
1646
GError *error = NULL;
1648
rb_debug ("starting stream %s on EOS from previous", pstream->uri);
1649
if (link_and_unblock_stream (pstream, &error) == FALSE) {
1650
emit_stream_error (pstream, error);
1653
g_object_unref (pstream);
1655
g_list_free (to_start);
1658
/* gstreamer message bus callback */
1660
rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *player)
1662
RBXFadeStream *stream;
1664
g_return_val_if_fail (player != NULL, FALSE);
1666
g_rec_mutex_lock (&player->priv->stream_list_lock);
1668
stream = find_stream_for_message (player, message);
1669
g_rec_mutex_unlock (&player->priv->stream_list_lock);
1671
switch (GST_MESSAGE_TYPE (message)) {
1672
case GST_MESSAGE_ERROR:
1675
GError *error, *sig_error;
1677
gboolean emit = TRUE;
1679
gst_message_parse_error (message, &error, &debug);
1681
if (stream == NULL) {
1682
rb_debug ("Couldn't find stream for error \"%s\": %s", error->message, debug);
1683
g_error_free (error);
1688
/* If we've already got an error, ignore 'internal data flow error'
1689
* type messages, as they're too generic to be helpful.
1691
if (stream->emitted_error &&
1692
error->domain == GST_STREAM_ERROR &&
1693
error->code == GST_STREAM_ERROR_FAILED) {
1694
rb_debug ("Ignoring generic error \"%s\"", error->message);
1698
code = rb_gst_error_get_error_code (error);
1701
rb_debug ("emitting error %s for stream %s", error->message, stream->uri);
1702
sig_error = g_error_new_literal (RB_PLAYER_ERROR,
1705
stream->emitted_error = TRUE;
1706
if (stream->emitted_playing == FALSE) {
1707
_rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
1709
_rb_player_emit_error (RB_PLAYER (player), stream->stream_data, sig_error);
1712
g_error_free (error);
1716
case GST_MESSAGE_TAG:
1717
if (stream == NULL) {
1718
rb_debug ("got tag message for unknown stream");
1721
gst_message_parse_tag (message, &tags);
1723
g_mutex_lock (&stream->lock);
1724
if (stream->emitted_playing) {
1725
gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
1726
gst_tag_list_free (tags);
1728
stream->tags = g_list_append (stream->tags, tags);
1730
g_mutex_unlock (&stream->lock);
1734
case GST_MESSAGE_DURATION:
1735
if (stream == NULL) {
1736
rb_debug ("got duration message for unknown stream");
1740
gst_message_parse_duration (message, &format, &duration);
1741
rb_debug ("got duration %" G_GINT64_FORMAT
1742
" for stream %s", duration, stream->uri);
1746
case GST_MESSAGE_APPLICATION:
1748
/* process fade messages and emit signals for
1751
const GstStructure *structure;
1754
structure = gst_message_get_structure (message);
1755
name = gst_structure_get_name (structure);
1756
if (stream == NULL) {
1757
rb_debug ("got application message %s for unknown stream", name);
1758
} else if (strcmp (name, STREAM_PLAYING_MESSAGE) == 0) {
1762
rb_debug ("got stream playing message for %s", stream->uri);
1763
_rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
1765
/* process any buffered tag lists we received while prerolling the stream */
1766
g_mutex_lock (&stream->lock);
1768
stream->tags = NULL;
1769
g_mutex_unlock (&stream->lock);
1771
for (t = l; t != NULL; t = t->next) {
1774
tags = (GstTagList *)t->data;
1775
rb_debug ("processing buffered taglist");
1776
gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, stream);
1777
gst_tag_list_free (tags);
1781
} else if (strcmp (name, FADE_IN_DONE_MESSAGE) == 0) {
1782
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), TRUE);
1783
} else if (strcmp (name, FADE_OUT_DONE_MESSAGE) == 0) {
1784
switch (stream->state) {
1786
/* stop the stream and dispose of it */
1787
rb_debug ("got fade-out-done for stream %s -> PENDING_REMOVE", stream->uri);
1788
g_mutex_lock (&stream->lock);
1789
stream->state = PENDING_REMOVE;
1790
g_mutex_unlock (&stream->lock);
1791
schedule_stream_reap (player);
1794
case FADING_OUT_PAUSED:
1796
/* try to seek back a bit to account for the fade */
1799
g_mutex_lock (&stream->lock);
1800
gst_element_query_position (stream->volume, GST_FORMAT_TIME, &pos);
1802
stream->seek_target = pos > PAUSE_FADE_LENGTH ? pos - PAUSE_FADE_LENGTH : 0;
1803
stream->state = SEEKING_PAUSED;
1804
rb_debug ("got fade-out-done for stream %s -> SEEKING_PAUSED [%" G_GINT64_FORMAT "]",
1805
stream->uri, stream->seek_target);
1807
stream->state = PAUSED;
1808
rb_debug ("got fade-out-done for stream %s -> PAUSED (position query failed)",
1811
g_mutex_unlock (&stream->lock);
1813
unlink_and_block_stream (stream);
1817
g_assert_not_reached ();
1819
} else if (strcmp (name, STREAM_EOS_MESSAGE) == 0) {
1820
/* emit EOS (if we aren't already reusing the stream), then unlink it.
1821
* the stream stay around so we can seek back in it.
1823
stream->needs_unlink = TRUE;
1824
if (stream->state != REUSING) {
1825
rb_debug ("got EOS message for stream %s -> PENDING_REMOVE", stream->uri);
1826
_rb_player_emit_eos (RB_PLAYER (player), stream->stream_data, FALSE);
1827
stream->state = PENDING_REMOVE;
1829
unlink_blocked_cb (stream->src_pad, NULL, stream);
1831
/* start playing any streams that were waiting on an EOS
1832
* if they finished preroll between when we posted the EOS
1833
* message on the stream thread and now.
1835
start_waiting_eos_streams (player);
1837
/* no need to emit EOS here, we already know what to do next */
1838
rb_debug ("got EOS message for stream %s in REUSING state", stream->uri);
1840
unlink_reuse_relink (player, stream);
1844
_rb_player_emit_event (RB_PLAYER (player), stream->stream_data, name, NULL);
1849
case GST_MESSAGE_BUFFERING:
1851
const GstStructure *s;
1854
s = gst_message_get_structure (message);
1855
if (!gst_structure_get_int (s, "buffer-percent", &progress)) {
1856
g_warning ("Could not get value from BUFFERING message");
1859
if (stream == NULL) {
1860
rb_debug ("got buffering message for unknown stream (%d)", progress);
1864
if (progress >= 100) {
1865
GError *error = NULL;
1866
switch (stream->state) {
1868
rb_debug ("stream %s is buffered, now waiting", stream->uri);
1869
stream->state = WAITING;
1877
rb_debug ("stream %s is buffered, now playing", stream->uri);
1878
if (actually_start_stream (stream, &error) == FALSE) {
1879
emit_stream_error (stream, error);
1884
rb_debug ("stream %s is buffered, resuming", stream->uri);
1885
link_and_unblock_stream (stream, &error);
1887
g_warning ("couldn't restart newly buffered stream: %s", error->message);
1888
g_clear_error (&error);
1893
switch (stream->state) {
1896
rb_debug ("still buffering, %d", progress);
1897
stream->state = PREROLLING;
1905
rb_debug ("fading out stream is buffering, abandoning it");
1906
stream->state = PENDING_REMOVE;
1907
schedule_stream_reap (player);
1908
/* might need to remove it immediately to avoid stalling adder? */
1910
/* since we're abandoning this stream, pretend it's not buffering */
1914
rb_debug ("stream buffering, stopping playback");
1915
unlink_and_block_stream (stream);
1920
_rb_player_emit_buffering (RB_PLAYER (player), stream->stream_data, progress);
1923
case GST_MESSAGE_ELEMENT:
1925
const GstStructure *s;
1928
if (gst_is_missing_plugin_message (message)) {
1929
rb_player_gst_xfade_handle_missing_plugin_message (player, stream, message);
1933
s = gst_message_get_structure (message);
1934
name = gst_structure_get_name (s);
1935
if ((strcmp (name, "imperfect-timestamp") == 0) ||
1936
(strcmp (name, "imperfect-offset") == 0)) {
1938
const char *uri = "unknown-stream";
1940
if (stream != NULL) {
1944
details = gst_structure_to_string (s);
1945
rb_debug_realf ("check-imperfect", __FILE__, __LINE__, TRUE, "%s: %s", uri, details);
1947
} else if (strcmp (name, "redirect") == 0) {
1948
const char *uri = gst_structure_get_string (s, "new-location");
1949
if (stream != NULL) {
1950
_rb_player_emit_redirect (RB_PLAYER (player), stream->stream_data, uri);
1952
rb_debug ("got redirect to %s, but no active stream found", uri);
1962
g_object_unref (stream);
1964
/* emit message signals too, so plugins can process bus messages */
1965
gst_bus_async_signal_func (bus, message, NULL);
1971
stream_source_setup_cb (GstElement *decoder, GstElement *source, RBXFadeStream *stream)
1973
rb_debug ("got source notification for stream %s", stream->uri);
1974
g_signal_emit (stream->player, signals[PREPARE_SOURCE], 0, stream->uri, source);
1977
/* links uridecodebin src pads to the rest of the output pipeline */
1979
stream_pad_added_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
1982
GstStructure *structure;
1983
const char *mediatype;
1986
/* make sure this is an audio pad */
1987
caps = gst_pad_query_caps (pad, NULL);
1989
caps = gst_pad_query_caps (pad, NULL);
1992
if (gst_caps_is_empty (caps) || gst_caps_is_any (caps)) {
1993
rb_debug ("got empty/any decoded caps. hmm?");
1994
gst_caps_unref (caps);
1998
structure = gst_caps_get_structure (caps, 0);
1999
mediatype = gst_structure_get_name (structure);
2000
if (g_str_has_prefix (mediatype, "audio/x-raw") == FALSE) {
2001
rb_debug ("got non-audio decoded caps: %s", mediatype);
2002
} else if (stream->decoder_linked) {
2003
/* probably should never happen */
2004
rb_debug ("hmm, decoder is already linked");
2006
rb_debug ("got decoded audio pad for stream %s", stream->uri);
2007
vpad = gst_element_get_static_pad (stream->identity, "sink");
2008
gst_pad_link (pad, vpad);
2009
gst_object_unref (vpad);
2010
stream->decoder_linked = TRUE;
2012
stream->decoder_pad = gst_object_ref (pad);
2015
gst_caps_unref (caps);
2019
stream_pad_removed_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
2021
if (pad == stream->decoder_pad) {
2022
rb_debug ("active output pad for stream %s removed", stream->uri);
2023
stream->decoder_linked = FALSE;
2025
gst_object_unref (stream->decoder_pad);
2026
stream->decoder_pad = NULL;
2030
/* handles EOS events on stream bins. since the pipeline as a whole
2031
* never goes EOS, we don't get an EOS bus message, so we have to handle
2034
* when an EOS event is received, a bus message is posted, and any streams
2035
* in the WAITING_EOS state are started.
2037
* when a new segment event is received, the stream base time is updated
2038
* (mostly for seeking)
2040
* flush events are dropped, as they're only relevant inside the stream bin.
2041
* flushing the adder or the output bin mostly just breaks everything.
2043
static GstPadProbeReturn
2044
stream_src_event_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
2050
event = GST_EVENT (info->data);
2052
switch (GST_EVENT_TYPE (event)) {
2054
rb_debug ("posting EOS message for stream %s", stream->uri);
2055
s = gst_structure_new_empty (STREAM_EOS_MESSAGE);
2056
msg = gst_message_new_application (GST_OBJECT (stream), s);
2057
gst_element_post_message (GST_ELEMENT (stream), msg);
2059
/* start playing any streams that were waiting on an EOS
2060
* (are we really allowed to do this on a stream thread?)
2062
start_waiting_eos_streams (stream->player);
2065
case GST_EVENT_SEGMENT:
2066
rb_debug ("got new segment for stream %s", stream->uri);
2067
g_mutex_lock (&stream->lock);
2068
adjust_stream_base_time (stream);
2069
g_mutex_unlock (&stream->lock);
2072
case GST_EVENT_FLUSH_STOP:
2073
case GST_EVENT_FLUSH_START:
2074
rb_debug ("dropping %s event for stream %s", GST_EVENT_TYPE_NAME (event), stream->uri);
2075
return GST_PAD_PROBE_DROP;
2078
rb_debug ("got %s event for stream %s", GST_EVENT_TYPE_NAME (event), stream->uri);
2082
return GST_PAD_PROBE_OK;
2086
* stream playback bin:
2088
* src [ ! queue ] ! decodebin ! audioconvert ! audioresample ! caps ! queue ! volume
2090
* the first queue is only added for non-local streams. the thresholds
2091
* and such are probably going to be configurable at some point,
2092
* since people seem to get all whiny if they don't have a buffer
2093
* size slider to play with.
2095
* the volume element is used for crossfading.
2097
static RBXFadeStream *
2098
create_stream (RBPlayerGstXFade *player, const char *uri, gpointer stream_data, GDestroyNotify stream_data_destroy)
2100
RBXFadeStream *stream;
2102
GArray *stream_filters = NULL;
2106
rb_debug ("creating new stream for %s (stream data %p)", uri, stream_data);
2107
stream = g_object_new (RB_TYPE_XFADE_STREAM, NULL, NULL);
2108
stream->player = g_object_ref (player);
2109
stream->stream_data = stream_data;
2110
stream->stream_data_destroy = stream_data_destroy;
2111
stream->uri = g_strdup (uri);
2112
stream->state = WAITING;
2114
stream->use_buffering = FALSE;
2115
for (i = 0; i < G_N_ELEMENTS (stream_schemes); i++) {
2116
if (gst_uri_has_protocol (uri, stream_schemes[i])) {
2117
stream->use_buffering = TRUE;
2122
/* kill the floating reference */
2123
gst_object_ref_sink (stream);
2124
gst_element_set_locked_state (GST_ELEMENT (stream), TRUE);
2125
stream->decoder = gst_element_factory_make ("uridecodebin", NULL);
2126
if (stream->decoder == NULL) {
2127
rb_debug ("unable to create uridecodebin");
2128
g_object_unref (stream);
2131
gst_object_ref (stream->decoder);
2132
g_object_set (stream->decoder, "uri", uri, NULL);
2134
/* connect uridecodebin to audioconvert when it creates its output pad */
2135
g_signal_connect_object (stream->decoder,
2137
G_CALLBACK (stream_source_setup_cb),
2140
g_signal_connect_object (stream->decoder,
2142
G_CALLBACK (stream_pad_added_cb),
2145
g_signal_connect_object (stream->decoder,
2147
G_CALLBACK (stream_pad_removed_cb),
2151
stream->identity = gst_element_factory_make ("identity", NULL);
2152
if (stream->identity == NULL) {
2153
rb_debug ("unable to create identity");
2154
g_object_unref (stream);
2158
stream->audioconvert = gst_element_factory_make ("audioconvert", NULL);
2159
if (stream->audioconvert == NULL) {
2160
rb_debug ("unable to create audio converter");
2161
g_object_unref (stream);
2164
gst_object_ref (stream->audioconvert);
2166
stream->audioresample = gst_element_factory_make ("audioresample", NULL);
2167
if (stream->audioresample == NULL) {
2168
rb_debug ("unable to create audio resample");
2169
g_object_unref (stream);
2172
gst_object_ref (stream->audioresample);
2174
stream->capsfilter = gst_element_factory_make ("capsfilter", NULL);
2175
if (stream->capsfilter == NULL) {
2176
rb_debug ("unable to create capsfilter");
2177
g_object_unref (stream);
2180
gst_object_ref (stream->capsfilter);
2182
caps = gst_caps_new_simple ("audio/x-raw",
2183
"format", G_TYPE_STRING, "S16LE", /* appropriate? */
2184
"channels", G_TYPE_INT, 2,
2185
"layout", G_TYPE_STRING, "interleaved",
2186
"rate", G_TYPE_INT, 44100,
2188
g_object_set (stream->capsfilter, "caps", caps, NULL);
2189
gst_caps_unref (caps);
2191
stream->volume = gst_element_factory_make ("volume", NULL);
2192
if (stream->volume == NULL) {
2193
rb_debug ("unable to create volume control");
2194
g_object_unref (stream);
2197
gst_object_ref (stream->volume);
2199
g_signal_connect_object (stream->volume,
2201
G_CALLBACK (volume_changed_cb),
2204
stream->fader = GST_TIMED_VALUE_CONTROL_SOURCE (gst_interpolation_control_source_new ());
2205
gst_timed_value_control_source_set (GST_TIMED_VALUE_CONTROL_SOURCE (stream->fader), 0, 0.1);
2206
g_object_set (stream->fader, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
2208
gst_object_add_control_binding (GST_OBJECT (stream->volume),
2209
gst_direct_control_binding_new (GST_OBJECT (stream->volume), "volume", GST_CONTROL_SOURCE (stream->fader)));
2211
stream->preroll = gst_element_factory_make ("queue", NULL);
2212
if (stream->preroll == NULL) {
2213
rb_debug ("unable to create preroll queue");
2214
g_object_unref (stream);
2217
/* decode at least a second during prerolling, to hopefully avoid underruns.
2218
* we clear this when prerolling is finished. bump the max buffer count up
2219
* a bit (from 200) as with some formats it often takes more buffers to
2220
* make up a whole second. don't really want to remove it altogether, though.
2222
g_object_set (stream->preroll,
2223
"min-threshold-time", GST_SECOND,
2224
"max-size-buffers", 1000,
2227
gst_bin_add_many (GST_BIN (stream),
2230
stream->audioconvert,
2231
stream->audioresample,
2236
gst_element_link_many (stream->audioconvert,
2237
stream->audioresample,
2243
if (rb_debug_matches ("check-imperfect", __FILE__)) {
2245
if (rb_debug_matches ("check-imperfect-timestamp", __FILE__)) {
2246
g_object_set (stream->identity, "check-imperfect-timestamp", TRUE, NULL);
2248
if (rb_debug_matches ("check-imperfect-offset", __FILE__)) {
2249
g_object_set (stream->identity, "check-imperfect-offset", TRUE, NULL);
2252
stream->src_pad = gst_element_get_static_pad (stream->volume, "src");
2254
/* link in any per-stream filters after the identity element, with an
2255
* audioconvert before each.
2257
tail = stream->identity;
2258
g_signal_emit (player, signals[GET_STREAM_FILTERS], 0, uri, &stream_filters);
2259
if (stream_filters != NULL) {
2261
for (i = 0; i < stream_filters->len; i++) {
2262
GValue *v = &g_array_index (stream_filters, GValue, i);
2264
GstElement *audioconvert;
2266
audioconvert = gst_element_factory_make ("audioconvert", NULL);
2267
filter = GST_ELEMENT (g_value_get_object (v));
2269
gst_bin_add_many (GST_BIN (stream), audioconvert, filter, NULL);
2270
gst_element_link_many (tail, audioconvert, filter, NULL);
2274
g_array_unref (stream_filters);
2276
gst_element_link (tail, stream->audioconvert);
2278
/* ghost the stream src pad up to the bin */
2279
stream->ghost_pad = gst_ghost_pad_new ("src", stream->src_pad);
2280
gst_element_add_pad (GST_ELEMENT (stream), stream->ghost_pad);
2282
/* watch for EOS events using a pad probe */
2283
gst_pad_add_probe (stream->src_pad,
2284
GST_PAD_PROBE_TYPE_EVENT_BOTH | GST_PAD_PROBE_TYPE_EVENT_FLUSH,
2285
(GstPadProbeCallback) stream_src_event_cb,
2289
/* use the pipeline bus even when not inside the pipeline (?) */
2290
gst_element_set_bus (GST_ELEMENT (stream), gst_element_get_bus (player->priv->pipeline));
2295
/* starts playback for a stream.
2296
* - links to adder and unblocks
2297
* - if play_type is CROSSFADE:
2298
* - starts the fade in of the new stream
2299
* - starts the fade out of the old stream
2300
* - sets the stream to PLAYING state
2301
* - if play_type is WAIT_EOS:
2302
* - if something is playing, set the stream to wait-eos state
2303
* - otherwise, starts it
2304
* - if play_type is REPLACE:
2305
* - stops any existing stream
2306
* - starts the new stream
2309
actually_start_stream (RBXFadeStream *stream, GError **error)
2311
RBPlayerGstXFade *player = stream->player;
2312
gboolean ret = TRUE;
2313
gboolean need_reap = FALSE;
2318
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);
2319
switch (stream->play_type) {
2320
case RB_PLAYER_PLAY_CROSSFADE:
2323
g_rec_mutex_lock (&player->priv->stream_list_lock);
2324
for (l = player->priv->streams; l != NULL; l = l->next) {
2325
RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2327
if (pstream == stream)
2330
switch (pstream->state) {
2333
rb_debug ("stream %s is playing; crossfading -> FADING_OUT", pstream->uri);
2334
to_fade = g_list_prepend (to_fade, g_object_ref (pstream));
2340
case SEEKING_PAUSED:
2343
rb_debug ("stream %s is paused; replacing it", pstream->uri);
2344
pstream->state = PENDING_REMOVE;
2346
case PENDING_REMOVE:
2355
g_rec_mutex_unlock (&player->priv->stream_list_lock);
2357
for (l = to_fade; l != NULL; l = l->next) {
2358
RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2359
double fade_out_start = 1.0f;
2360
gint64 fade_out_time = stream->crossfade;
2362
switch (pstream->state) {
2364
/* fade out from where the fade in got up to */
2365
g_object_get (pstream->volume, "volume", &fade_out_start, NULL);
2366
fade_out_time = (gint64)(((double) stream->crossfade) * fade_out_start);
2370
start_stream_fade (pstream, fade_out_start, 0.0f, fade_out_time);
2371
pstream->state = FADING_OUT;
2373
start_stream_fade (stream, 0.0f, 1.0f, stream->crossfade);
2377
/* shouldn't happen, but ignore it if it does */
2381
g_object_unref (pstream);
2383
g_list_free (to_fade);
2385
if (stream->fading == FALSE) {
2386
rb_debug ("stream isn't fading; setting volume to 1.0");
2387
gst_timed_value_control_source_set (GST_TIMED_VALUE_CONTROL_SOURCE (stream->fader), 0, 0.1);
2388
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), TRUE);
2391
ret = link_and_unblock_stream (stream, error);
2394
case RB_PLAYER_PLAY_AFTER_EOS:
2396
g_rec_mutex_lock (&player->priv->stream_list_lock);
2399
for (l = player->priv->streams; l != NULL; l = l->next) {
2400
RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2401
if (pstream == stream)
2404
switch (pstream->state) {
2408
rb_debug ("stream %s is already playing", pstream->uri);
2412
rb_debug ("stream %s is paused; replacing it", pstream->uri);
2413
pstream->state = PENDING_REMOVE;
2414
case PENDING_REMOVE:
2422
g_rec_mutex_unlock (&player->priv->stream_list_lock);
2425
/* wait for current stream's EOS */
2426
rb_debug ("existing playing stream found; waiting for its EOS -> WAITING_EOS");
2427
stream->state = WAITING_EOS;
2428
stream->starting_eos = FALSE;
2430
rb_debug ("no playing stream found, so starting immediately");
2431
ret = link_and_unblock_stream (stream, error);
2435
case RB_PLAYER_PLAY_REPLACE:
2436
/* replace any existing playing stream */
2437
g_rec_mutex_lock (&player->priv->stream_list_lock);
2439
for (l = player->priv->streams; l != NULL; l = l->next) {
2440
RBXFadeStream *pstream = (RBXFadeStream *)l->data;
2441
if (pstream == stream)
2444
switch (pstream->state) {
2448
case PENDING_REMOVE:
2450
rb_debug ("stopping stream %s (replaced by new stream)", pstream->uri);
2452
pstream->state = PENDING_REMOVE;
2461
g_rec_mutex_unlock (&player->priv->stream_list_lock);
2463
ret = link_and_unblock_stream (stream, error);
2467
g_assert_not_reached ();
2471
schedule_stream_reap (player);
2477
/* called on a streaming thread when the stream src pad is blocked
2478
* (that is, when prerolling is complete). in some situations we
2479
* start playback immediately, otherwise we wait for something else
2482
static GstPadProbeReturn
2483
stream_src_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
2485
GError *error = NULL;
2486
gboolean start_stream = FALSE;
2488
g_mutex_lock (&stream->lock);
2489
if (stream->src_blocked) {
2490
/*rb_debug ("stream %s already blocked", stream->uri);*/
2491
g_mutex_unlock (&stream->lock);
2492
return GST_PAD_PROBE_OK;
2494
stream->src_blocked = TRUE;
2496
g_object_set (stream->preroll,
2497
"min-threshold-time", G_GINT64_CONSTANT (0),
2498
"max-size-buffers", 200, /* back to normal value */
2501
if (stream->use_buffering) {
2502
rb_debug ("stream %s requires buffering", stream->uri);
2503
switch (stream->state) {
2505
post_stream_playing_message (stream, TRUE);
2510
g_mutex_unlock (&stream->lock);
2511
return GST_PAD_PROBE_OK;
2514
/* update stream state */
2515
switch (stream->state) {
2517
rb_debug ("stream %s is prerolled, not starting yet -> WAITING", stream->uri);
2518
stream->state = WAITING;
2521
rb_debug ("stream %s is prerolled, need to start it", stream->uri);
2522
start_stream = TRUE;
2525
rb_debug ("didn't expect to get preroll completion callback in this state (%d)", stream->state);
2529
g_mutex_unlock (&stream->lock);
2531
if (start_stream == TRUE) {
2532
/* not sure this is actually an acceptable thing to do on a streaming thread.. */
2533
if (actually_start_stream (stream, &error) == FALSE) {
2534
emit_stream_error (stream, error);
2538
return GST_PAD_PROBE_OK;
2542
* starts prerolling for a stream.
2543
* since the stream isn't linked to anything yet, we
2544
* block the src pad. when the pad block callback
2545
* is called, prerolling is complete and the stream
2546
* can be linked and played immediately if required.
2548
* must be called *without* the stream list lock?
2551
preroll_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
2553
GstStateChangeReturn state;
2554
GstMessage *message;
2557
stream->block_probe_id =
2558
gst_pad_add_probe (stream->src_pad,
2559
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
2560
(GstPadProbeCallback) stream_src_blocked_cb,
2564
stream->emitted_playing = FALSE;
2565
stream->state = PREROLLING;
2566
state = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PAUSED);
2568
case GST_STATE_CHANGE_FAILURE:
2569
rb_debug ("preroll for stream %s failed (state change failed)", stream->uri);
2571
/* process bus messages in case we got a redirect for this stream */
2572
bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2573
message = gst_bus_pop (bus);
2574
while (message != NULL) {
2575
rb_player_gst_xfade_bus_cb (bus, message, player);
2576
gst_message_unref (message);
2577
message = gst_bus_pop (bus);
2579
g_object_unref (bus);
2582
case GST_STATE_CHANGE_NO_PREROLL:
2583
rb_debug ("no preroll for stream %s, setting to PLAYING instead?", stream->uri);
2584
gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
2586
case GST_STATE_CHANGE_SUCCESS:
2587
case GST_STATE_CHANGE_ASYNC:
2588
/* uridecodebin returns SUCCESS from state changes when streaming, so we can't
2589
* use that to figure out what to do next. instead, we wait for pads to be added
2590
* and for our pad block callbacks to be called.
2594
g_assert_not_reached();
2599
* returns the RBXFadeStream, playback position, and duration of the current
2603
get_times_and_stream (RBPlayerGstXFade *player, RBXFadeStream **pstream, gint64 *pos, gint64 *duration)
2605
gboolean got_time = FALSE;
2606
gboolean buffering = FALSE;
2607
RBXFadeStream *stream;
2609
if (player->priv->pipeline == NULL)
2612
g_rec_mutex_lock (&player->priv->stream_list_lock);
2614
/* first look for a network stream that is buffering during preroll */
2615
stream = find_stream_by_state (player, PREROLLING | PREROLL_PLAY);
2616
if (stream != NULL) {
2617
if (stream->emitted_fake_playing == FALSE) {
2618
g_object_unref (stream);
2621
rb_debug ("found buffering stream %s as current", stream->uri);
2626
/* otherwise, the stream that is playing */
2627
if (stream == NULL) {
2628
stream = find_stream_by_state (player, FADING_IN | PLAYING | FADING_OUT_PAUSED | PAUSED | PENDING_REMOVE | REUSING);
2630
g_rec_mutex_unlock (&player->priv->stream_list_lock);
2632
if (stream != NULL) {
2633
if (pstream != NULL) {
2640
} else if (stream->state == PAUSED) {
2643
gst_element_query_position (stream->volume, GST_FORMAT_TIME, pos);
2645
/* for playing streams, we subtract the current output position
2646
* (a running counter generated by the adder) from the position
2647
* at which we started playback.
2650
gst_element_query_position (player->priv->pipeline, GST_FORMAT_TIME, pos);
2652
*pos -= stream->base_time;
2654
rb_debug ("position query failed");
2659
if (duration != NULL) {
2661
/* queries are supposed to go to sinks, but the closest thing we
2662
* have in the stream bin is the volume element, which is the last
2665
gst_element_query_duration (stream->volume, GST_FORMAT_TIME, duration);
2668
if (pstream == NULL) {
2669
g_object_unref (stream);
2672
rb_debug ("not playing");
2679
tick_timeout (RBPlayerGstXFade *player)
2682
gint64 duration = -1;
2683
RBXFadeStream *stream = NULL;
2685
if (get_times_and_stream (player, &stream, &pos, &duration)) {
2686
_rb_player_emit_tick (RB_PLAYER (player), stream->stream_data, pos, duration);
2687
g_object_unref (stream);
2694
emit_volume_changed_idle (RBPlayerGstXFade *player)
2698
if (GST_IS_STREAM_VOLUME (player->priv->volume_handler)) {
2699
vol = gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
2700
GST_STREAM_VOLUME_FORMAT_CUBIC);
2702
vol = player->priv->cur_volume;
2705
_rb_player_emit_volume_changed (RB_PLAYER (player), vol);
2710
stream_volume_changed (GObject *element, GParamSpec *pspec, RBPlayerGstXFade *player)
2714
g_object_get (element, "volume", &v, NULL);
2715
player->priv->cur_volume = v;
2717
g_idle_add ((GSourceFunc) emit_volume_changed_idle, player);
2721
* output sink + adder pipeline:
2723
* outputcaps = audio/x-raw,channels=2,rate=44100,format=S16LE
2724
* outputbin = outputcaps ! volume ! filterbin ! audioconvert ! audioresample ! tee ! queue ! audiosink
2725
* silencebin = audiotestsrc wave=silence ! outputcaps
2727
* pipeline = silencebin ! adder ! outputbin
2729
* the tee in output bin has branches attached to it using the
2730
* RBPlayerGstTee interface. filterbin contains elements inserted
2731
* using the RBPlayerGstFilter interface.
2733
* silencebin is there for two reasons:
2734
* - lets us start the sink without having any streams playing
2735
* - probably helps keep things from falling over between streams
2739
add_bus_watch (RBPlayerGstXFade *player)
2743
bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2744
player->priv->bus_watch_id = gst_bus_add_watch (bus, (GstBusFunc) rb_player_gst_xfade_bus_cb, player);
2745
gst_object_unref (bus);
2749
start_sink_locked (RBPlayerGstXFade *player, GList **messages, GError **error)
2751
GstStateChangeReturn sr;
2753
GError *generic_error = NULL;
2756
g_set_error (&generic_error,
2758
RB_PLAYER_ERROR_INTERNAL, /* ? */
2759
_("Failed to open output device"));
2761
rb_debug ("starting sink");
2763
/* first, start the output bin.
2764
* this won't preroll until we start the silence bin.
2766
sr = gst_element_set_state (player->priv->outputbin, GST_STATE_PAUSED);
2767
if (sr == GST_STATE_CHANGE_FAILURE) {
2768
rb_debug ("output bin state change failed");
2769
g_propagate_error (error, generic_error);
2773
/* then the adder */
2774
sr = gst_element_set_state (player->priv->adder, GST_STATE_PAUSED);
2775
if (sr == GST_STATE_CHANGE_FAILURE) {
2776
rb_debug ("adder state change failed");
2777
g_propagate_error (error, generic_error);
2781
/* then the silence bin */
2782
sr = gst_element_set_state (player->priv->silencebin, GST_STATE_PAUSED);
2783
if (sr == GST_STATE_CHANGE_FAILURE) {
2784
rb_debug ("silence bin state change failed");
2785
g_propagate_error (error, generic_error);
2789
/* now wait for everything to finish */
2791
bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
2793
GstMessage *message;
2798
message = gst_bus_timed_pop (bus, GST_SECOND * 5);
2799
if (message == NULL) {
2800
rb_debug ("sink is taking too long to start..");
2801
g_propagate_error (error, generic_error);
2802
gst_object_unref (bus);
2806
switch (GST_MESSAGE_TYPE (message)) {
2807
case GST_MESSAGE_ERROR:
2810
GError *gst_error = NULL;
2811
RBXFadeStream *stream;
2813
/* we only want to process errors from the sink here.
2814
* errors from streams should go to the normal message handler.
2816
stream = find_stream_for_message (player, message);
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);
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);
2827
if (error != NULL && *error == NULL) {
2828
/* Translators: the parameter here is an error message */
2831
RB_PLAYER_ERROR_INTERNAL, /* ? */
2832
_("Failed to open output device: %s"),
2833
gst_error->message);
2835
g_error_free (gst_error);
2836
g_error_free (generic_error);
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);
2847
case GST_MESSAGE_STATE_CHANGED:
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");
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");
2864
/* save the message to pass to the bus callback once we've dropped
2867
*messages = g_list_append (*messages, gst_message_ref (message));
2871
gst_message_unref (message);
2873
gst_object_unref (bus);
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.
2884
player->priv->volume_applied = 1;
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;
2893
g_signal_connect_object (player->priv->volume_handler,
2895
G_CALLBACK (stream_volume_changed),
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);
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);
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);
2920
rb_debug ("sink playing");
2921
player->priv->sink_state = SINK_PLAYING;
2923
/* set the pipeline to PLAYING so it selects a clock */
2924
gst_element_set_state (player->priv->pipeline, GST_STATE_PLAYING);
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?
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,
2943
start_sink (RBPlayerGstXFade *player, GError **error)
2945
GList *messages = NULL;
2950
g_rec_mutex_lock (&player->priv->sink_lock);
2951
switch (player->priv->sink_state) {
2953
g_assert_not_reached ();
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);
2968
g_assert_not_reached ();
2970
g_rec_mutex_unlock (&player->priv->sink_lock);
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);
2976
gst_object_unref (bus);
2978
rb_list_destroy_free (messages, (GDestroyNotify) gst_mini_object_unref);
2983
stop_sink (RBPlayerGstXFade *player)
2986
GstStateChangeReturn sr;
2988
switch (player->priv->sink_state) {
2990
rb_debug ("stopping sink");
2992
if (player->priv->tick_timeout_id != 0) {
2993
g_source_remove (player->priv->tick_timeout_id);
2994
player->priv->tick_timeout_id = 0;
2997
sr = gst_element_set_state (player->priv->outputbin, GST_STATE_READY);
2998
if (sr == GST_STATE_CHANGE_FAILURE) {
2999
rb_debug ("couldn't stop output bin");
3003
sr = gst_element_set_state (player->priv->adder, GST_STATE_READY);
3004
if (sr == GST_STATE_CHANGE_FAILURE) {
3005
rb_debug ("couldn't stop adder");
3009
sr = gst_element_set_state (player->priv->silencebin, GST_STATE_READY);
3010
if (sr == GST_STATE_CHANGE_FAILURE) {
3011
rb_debug ("couldn't stop silence bin");
3015
/* try stopping the sink, but don't worry if we can't */
3016
sr = gst_element_set_state (player->priv->sink, GST_STATE_NULL);
3017
if (sr == GST_STATE_CHANGE_FAILURE) {
3018
rb_debug ("couldn't set audio sink to NULL state");
3021
if (player->priv->volume_handler) {
3022
g_object_unref (player->priv->volume_handler);
3023
player->priv->volume_handler = NULL;
3026
/* set the pipeline to READY so we can make it select a clock when we
3027
* start the sink again. everything inside the pipeline has its state
3028
* locked, so this doesn't affect anything else.
3030
gst_element_set_state (player->priv->pipeline, GST_STATE_READY);
3032
player->priv->sink_state = SINK_STOPPED;
3047
create_sink (RBPlayerGstXFade *player, GError **error)
3049
const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
3050
GstElement *audiotestsrc;
3051
GstElement *audioconvert;
3052
GstElement *audioresample;
3053
GstElement *capsfilter;
3057
GstPad *outputghostpad;
3060
GstPad *addersrcpad;
3061
GstPadLinkReturn plr;
3065
if (player->priv->sink_state != SINK_NULL)
3069
* 44100Hz is about the most reasonable thing to use;
3070
* we have audioconvert+audioresample afterwards in
3071
* case the output device doesn't actually support
3074
caps = gst_caps_new_simple ("audio/x-raw",
3075
"format" , G_TYPE_STRING, "S16LE",
3076
"channels", G_TYPE_INT, 2,
3077
"rate", G_TYPE_INT, 44100,
3078
"layout", G_TYPE_STRING, "interleaved",
3081
player->priv->pipeline = gst_pipeline_new ("rbplayer");
3082
add_bus_watch (player);
3083
g_object_notify (G_OBJECT (player), "bus");
3085
player->priv->outputbin = gst_bin_new ("outputbin");
3086
gst_element_set_locked_state (player->priv->outputbin, TRUE);
3087
player->priv->adder = gst_element_factory_make ("adder", "outputadder");
3088
player->priv->capsfilter = gst_element_factory_make ("capsfilter", "outputcapsfilter");
3089
audioconvert = gst_element_factory_make ("audioconvert", "outputconvert");
3090
audioresample = gst_element_factory_make ("audioresample", "outputresample");
3091
player->priv->tee = gst_element_factory_make ("tee", "outputtee");
3092
queue = gst_element_factory_make ("queue", NULL);
3093
player->priv->volume = gst_element_factory_make ("volume", "outputvolume");
3094
player->priv->filterbin = rb_gst_create_filter_bin ();
3095
capsfilter = gst_element_factory_make ("capsfilter", NULL);
3096
if (player->priv->pipeline == NULL ||
3097
player->priv->adder == NULL ||
3098
player->priv->capsfilter == NULL ||
3099
audioconvert == NULL ||
3100
audioresample == NULL ||
3101
player->priv->tee == NULL ||
3103
player->priv->volume == NULL ||
3104
player->priv->filterbin == NULL ||
3105
capsfilter == NULL) {
3106
/* we could include the element name in the error message,
3107
* but these are all fundamental elements that are always
3112
RB_PLAYER_ERROR_GENERAL,
3113
_("Failed to create GStreamer element; check your installation"));
3117
for (i = 0; i < G_N_ELEMENTS (try_sinks); i++) {
3118
player->priv->sink = rb_player_gst_try_audio_sink (try_sinks[i], NULL);
3119
if (player->priv->sink != NULL) {
3123
if (player->priv->sink == NULL) {
3126
RB_PLAYER_ERROR_GENERAL,
3127
_("Failed to create audio output element; check your installation"));
3131
g_object_set (player->priv->capsfilter, "caps", caps, NULL);
3132
g_object_set (capsfilter, "caps", caps, NULL);
3134
g_object_set (queue, "max-size-buffers", 10, NULL);
3136
gst_bin_add_many (GST_BIN (player->priv->outputbin),
3137
player->priv->capsfilter,
3138
player->priv->volume,
3139
player->priv->filterbin,
3147
if (gst_element_link_many (player->priv->capsfilter,
3148
player->priv->volume,
3149
player->priv->filterbin,
3157
g_warning ("minus one");
3160
RB_PLAYER_ERROR_GENERAL,
3161
_("Failed to link GStreamer pipeline; check your installation"));
3165
filterpad = gst_element_get_static_pad (player->priv->capsfilter, "sink");
3166
outputghostpad = gst_ghost_pad_new ("sink", filterpad);
3167
gst_element_add_pad (player->priv->outputbin, outputghostpad);
3168
gst_object_unref (filterpad);
3170
/* create silence bin */
3171
player->priv->silencebin = gst_bin_new ("silencebin");
3172
audiotestsrc = gst_element_factory_make ("audiotestsrc", "silence");
3173
g_object_set (audiotestsrc, "wave", 4, NULL);
3175
audioconvert = gst_element_factory_make ("audioconvert", "silenceconvert");
3177
capsfilter = gst_element_factory_make ("capsfilter", "silencecapsfilter");
3178
g_object_set (capsfilter, "caps", caps, NULL);
3179
gst_caps_unref (caps);
3181
if (audiotestsrc == NULL ||
3182
audioconvert == NULL ||
3183
capsfilter == NULL) {
3186
RB_PLAYER_ERROR_GENERAL,
3187
_("Failed to create GStreamer element; check your installation"));
3191
gst_bin_add_many (GST_BIN (player->priv->silencebin),
3196
if (gst_element_link_many (audiotestsrc,
3203
RB_PLAYER_ERROR_GENERAL,
3204
_("Failed to link GStreamer pipeline; check your installation"));
3208
filterpad = gst_element_get_static_pad (capsfilter, "src");
3209
ghostpad = gst_ghost_pad_new (NULL, filterpad);
3210
gst_element_add_pad (player->priv->silencebin, ghostpad);
3211
gst_object_unref (filterpad);
3214
* - add everything to the pipeline
3215
* - link adder to output bin
3216
* - link silence bin to adder
3218
gst_bin_add_many (GST_BIN (player->priv->pipeline),
3219
player->priv->adder,
3220
player->priv->outputbin,
3221
player->priv->silencebin,
3224
addersrcpad = gst_element_get_static_pad (player->priv->adder, "src");
3225
plr = gst_pad_link (addersrcpad, outputghostpad);
3226
if (plr != GST_PAD_LINK_OK) {
3230
RB_PLAYER_ERROR_GENERAL,
3231
_("Failed to link GStreamer pipeline; check your installation"));
3235
reqpad = gst_element_get_request_pad (player->priv->adder, "sink_%u");
3236
if (reqpad == NULL) {
3240
RB_PLAYER_ERROR_GENERAL,
3241
_("Failed to link GStreamer pipeline; check your installation"));
3245
plr = gst_pad_link (ghostpad, reqpad);
3246
if (plr != GST_PAD_LINK_OK) {
3247
g_warning ("three");
3250
RB_PLAYER_ERROR_GENERAL,
3251
_("Failed to link GStreamer pipeline; check your installation"));
3255
/* add any tees and filters that were waiting for us */
3256
for (l = player->priv->waiting_tees; l != NULL; l = g_list_next (l)) {
3257
rb_player_gst_tee_add_tee (RB_PLAYER_GST_TEE (player), GST_ELEMENT (l->data));
3259
g_list_free (player->priv->waiting_tees);
3260
player->priv->waiting_tees = NULL;
3262
for (l = player->priv->waiting_filters; l != NULL; l = g_list_next (l)) {
3263
rb_player_gst_filter_add_filter (RB_PLAYER_GST_FILTER (player), GST_ELEMENT (l->data));
3265
g_list_free (player->priv->waiting_filters);
3266
player->priv->waiting_filters = NULL;
3268
player->priv->sink_state = SINK_STOPPED;
3275
rb_player_gst_xfade_open (RBPlayer *iplayer,
3277
gpointer stream_data,
3278
GDestroyNotify stream_data_destroy,
3281
RBXFadeStream *stream;
3282
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3283
gboolean reused = FALSE;
3286
/* create sink if we don't already have one */
3287
if (create_sink (player, error) == FALSE)
3290
/* see if anyone wants us to reuse an existing stream */
3291
g_rec_mutex_lock (&player->priv->stream_list_lock);
3292
for (t = player->priv->streams; t != NULL; t = t->next) {
3293
RBXFadeStream *stream = (RBXFadeStream *)t->data;
3295
switch (stream->state) {
3297
case PENDING_REMOVE:
3300
case SEEKING_PAUSED:
3309
case FADING_OUT_PAUSED:
3312
g_signal_emit (player,
3313
signals[CAN_REUSE_STREAM], 0,
3314
uri, stream->uri, GST_ELEMENT (stream),
3320
rb_debug ("reusing stream %s for new stream %s", stream->uri, uri);
3321
stream->state = REUSING;
3322
stream->new_uri = g_strdup (uri);
3323
stream->new_stream_data = stream_data;
3324
stream->new_stream_data_destroy = stream_data_destroy;
3326
/* move the stream to the front of the list so it'll be started when
3327
* _play is called (it's probably already there, but just in case..)
3329
player->priv->streams = g_list_remove (player->priv->streams, stream);
3330
player->priv->streams = g_list_prepend (player->priv->streams, stream);
3334
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3339
/* construct new stream */
3340
stream = create_stream (player, uri, stream_data, stream_data_destroy);
3341
if (stream == NULL) {
3342
rb_debug ("unable to create pipeline to play %s", uri);
3345
RB_PLAYER_ERROR_GENERAL,
3346
_("Failed to create GStreamer pipeline to play %s"),
3351
g_rec_mutex_lock (&player->priv->stream_list_lock);
3352
player->priv->streams = g_list_prepend (player->priv->streams, stream);
3353
dump_stream_list (player);
3354
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3356
/* start prerolling it */
3357
preroll_stream (player, stream);
3363
stop_sink_later (RBPlayerGstXFade *player)
3365
g_rec_mutex_lock (&player->priv->sink_lock);
3366
player->priv->stop_sink_id = 0;
3367
if (g_atomic_int_get (&player->priv->linked_streams) == 0) {
3370
g_rec_mutex_unlock (&player->priv->sink_lock);
3376
maybe_stop_sink (RBPlayerGstXFade *player)
3378
g_rec_mutex_lock (&player->priv->sink_lock);
3379
if (player->priv->stop_sink_id == 0) {
3380
player->priv->stop_sink_id =
3381
g_timeout_add (1000,
3382
(GSourceFunc) stop_sink_later,
3385
g_rec_mutex_unlock (&player->priv->sink_lock);
3389
rb_player_gst_xfade_close (RBPlayer *iplayer, const char *uri, GError **error)
3391
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3392
gboolean ret = TRUE;
3398
/* need to copy the list as unlink_and_dispose_stream modifies it */
3399
g_rec_mutex_lock (&player->priv->stream_list_lock);
3400
list = g_list_copy (player->priv->streams);
3401
for (l = list; l != NULL; l = l->next) {
3402
RBXFadeStream *stream = (RBXFadeStream *)l->data;
3403
g_object_ref (stream);
3405
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3407
for (l = list; l != NULL; l = l->next) {
3408
RBXFadeStream *stream = (RBXFadeStream *)l->data;
3409
unlink_and_dispose_stream (player, stream);
3410
g_object_unref (stream);
3414
/* just stop and close the stream for the specified uri */
3415
RBXFadeStream *stream;
3417
g_rec_mutex_lock (&player->priv->stream_list_lock);
3418
stream = find_stream_by_uri (player, uri);
3419
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3421
if (stream != NULL) {
3422
unlink_and_dispose_stream (player, stream);
3423
g_object_unref (stream);
3425
rb_debug ("can't find stream for %s", uri);
3426
/* XXX set error ?*/
3436
rb_player_gst_xfade_opened (RBPlayer *iplayer)
3438
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3439
RBXFadeStream *stream;
3440
gboolean opened = FALSE;
3442
/* maybe replace this with just a flag somewhere? */
3444
g_rec_mutex_lock (&player->priv->stream_list_lock);
3446
stream = find_stream_by_state (player, PREROLLING | PREROLL_PLAY | WAITING_EOS | WAITING | FADING_IN | PLAYING | PAUSED);
3447
if (stream != NULL) {
3449
g_object_unref (stream);
3452
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3458
rb_player_gst_xfade_play (RBPlayer *iplayer,
3459
RBPlayerPlayType play_type,
3463
RBXFadeStream *stream;
3465
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3466
gboolean ret = TRUE;
3468
g_rec_mutex_lock (&player->priv->stream_list_lock);
3470
/* is there anything to play? */
3471
if (player->priv->streams == NULL) {
3474
RB_PLAYER_ERROR_GENERAL,
3475
"Nothing to play"); /* should never happen */
3477
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3481
stream = g_list_first (player->priv->streams)->data;
3482
g_object_ref (stream);
3483
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3485
/* make sure the sink is playing */
3486
if (start_sink (player, error) == FALSE) {
3487
g_object_unref (stream);
3491
g_mutex_lock (&stream->lock);
3493
rb_debug ("playing stream %s, play type %d, crossfade %" G_GINT64_FORMAT, stream->uri, play_type, crossfade);
3495
/* handle transitional states while holding the lock, and handle states that
3496
* require action outside it (lock precedence, mostly)
3498
switch (stream->state) {
3501
rb_debug ("stream %s is prerolling; will start playback once prerolling is complete -> PREROLL_PLAY", stream->uri);
3502
stream->play_type = play_type;
3503
stream->crossfade = crossfade;
3504
stream->state = PREROLL_PLAY;
3507
case SEEKING_PAUSED:
3508
rb_debug ("unpausing seeking stream %s", stream->uri);
3509
stream->state = SEEKING;
3512
case PENDING_REMOVE:
3513
rb_debug ("hmm, can't play streams in PENDING_REMOVE state..");
3520
stream_state = stream->state;
3521
g_mutex_unlock (&stream->lock);
3523
/* is the head stream already playing? */
3524
switch (stream_state) {
3527
case FADING_OUT_PAUSED:
3531
rb_debug ("stream %s is already playing", stream->uri);
3532
_rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
3536
rb_debug ("unpausing stream %s", stream->uri);
3537
start_stream_fade (stream, 0.0f, 1.0f, PAUSE_FADE_LENGTH);
3538
ret = link_and_unblock_stream (stream, error);
3543
stream->play_type = play_type;
3544
stream->crossfade = crossfade;
3545
ret = actually_start_stream (stream, error);
3549
switch (play_type) {
3550
case RB_PLAYER_PLAY_REPLACE:
3551
case RB_PLAYER_PLAY_CROSSFADE:
3552
/* probably should split this into two states.. */
3553
if (stream->src_blocked) {
3554
rb_debug ("reusing and restarting paused stream %s", stream->uri);
3555
reuse_stream (stream);
3556
ret = link_and_unblock_stream (stream, error);
3558
rb_debug ("unlinking stream %s for reuse", stream->uri);
3559
unlink_and_block_stream (stream);
3562
case RB_PLAYER_PLAY_AFTER_EOS:
3563
rb_debug ("waiting for EOS before reusing stream %s", stream->uri);
3572
g_object_unref (stream);
3578
rb_player_gst_xfade_pause (RBPlayer *iplayer)
3580
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3582
GList *to_fade = NULL;
3583
gboolean done = FALSE;
3584
double fade_out_start = 1.0f;
3585
gint64 fade_out_time = PAUSE_FADE_LENGTH;
3587
g_rec_mutex_lock (&player->priv->stream_list_lock);
3589
for (l = player->priv->streams; l != NULL; l = l->next) {
3590
RBXFadeStream *stream;
3591
stream = (RBXFadeStream *)l->data;
3592
switch (stream->state) {
3595
rb_debug ("stream %s is not yet playing, can't pause", stream->uri);
3600
rb_debug ("stream %s is prerolling, can't pause", stream->uri);
3604
rb_debug ("stream %s is being reused, can't pause", stream->uri);
3608
case SEEKING_PAUSED:
3609
case FADING_OUT_PAUSED:
3610
rb_debug ("stream %s is already paused", stream->uri);
3616
rb_debug ("pausing stream %s -> FADING_OUT_PAUSED", stream->uri);
3617
to_fade = g_list_prepend (to_fade, g_object_ref (stream));
3622
rb_debug ("pausing seeking stream %s -> SEEKING_PAUSED", stream->uri);
3623
stream->state = SEEKING_PAUSED;
3627
rb_debug ("stream %s is seeking after EOS -> SEEKING_PAUSED", stream->uri);
3628
stream->state = SEEKING_PAUSED;
3633
rb_debug ("stream %s is fading out, can't be bothered pausing it", stream->uri);
3636
case PENDING_REMOVE:
3637
rb_debug ("stream %s is done, can't pause", stream->uri);
3645
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3647
for (l = to_fade; l != NULL; l = l->next) {
3648
RBXFadeStream *stream = (RBXFadeStream *)l->data;
3650
switch (stream->state) {
3652
g_object_get (stream->volume, "volume", &fade_out_start, NULL);
3653
fade_out_time = (gint64)(((double) PAUSE_FADE_LENGTH) * fade_out_start);
3656
stream->state = FADING_OUT_PAUSED;
3657
start_stream_fade (stream, fade_out_start, 0.0f, fade_out_time);
3660
/* shouldn't happen, but ignore it if it does */
3664
g_object_unref (stream);
3666
g_list_free (to_fade);
3669
rb_debug ("couldn't find a stream to pause");
3673
rb_player_gst_xfade_playing (RBPlayer *iplayer)
3675
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3676
gboolean playing = FALSE;
3677
RBXFadeStream *stream;
3679
if (player->priv->sink_state != SINK_PLAYING)
3682
/* XXX maybe replace with just a flag? */
3684
g_rec_mutex_lock (&player->priv->stream_list_lock);
3686
stream = find_stream_by_state (player, PLAYING | FADING_IN);
3687
if (stream != NULL) {
3689
g_object_unref (stream);
3691
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3697
rb_player_gst_xfade_set_volume (RBPlayer *iplayer, float volume)
3699
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3701
player->priv->volume_changed++;
3702
if (player->priv->volume_handler != NULL) {
3703
gdouble v = (gdouble)volume;
3705
/* maybe use a controller here for smoother changes? */
3706
if (GST_IS_STREAM_VOLUME (player->priv->volume_handler)) {
3707
gst_stream_volume_set_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
3708
GST_STREAM_VOLUME_FORMAT_CUBIC, v);
3710
g_object_set (player->priv->volume_handler, "volume", v, NULL);
3712
player->priv->volume_applied = player->priv->volume_changed;
3714
player->priv->cur_volume = volume;
3719
rb_player_gst_xfade_get_volume (RBPlayer *iplayer)
3721
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3723
if (GST_IS_STREAM_VOLUME (player->priv->volume_handler))
3724
return gst_stream_volume_get_volume (GST_STREAM_VOLUME (player->priv->volume_handler),
3725
GST_STREAM_VOLUME_FORMAT_CUBIC);
3727
return player->priv->cur_volume;
3731
rb_player_gst_xfade_seekable (RBPlayer *iplayer)
3733
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3734
gboolean can_seek = TRUE;
3735
RBXFadeStream *stream;
3737
/* is this supposed to query the most recently opened stream,
3738
* or the current playing stream? I really don't know.
3740
g_rec_mutex_lock (&player->priv->stream_list_lock);
3741
stream = find_stream_by_state (player, FADING_IN | PAUSED | PLAYING);
3742
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3745
GstQuery *query = NULL;
3746
query = gst_query_new_seeking (GST_FORMAT_TIME);
3747
if (gst_element_query (stream->volume, query)) {
3748
gst_query_parse_seeking (query, NULL, &can_seek, NULL, NULL);
3750
gst_query_unref (query);
3752
query = gst_query_new_duration (GST_FORMAT_TIME);
3753
can_seek = gst_element_query (stream->volume, query);
3755
gst_query_unref (query);
3756
g_object_unref (stream);
3763
rb_player_gst_xfade_set_time (RBPlayer *iplayer, gint64 time)
3765
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3766
RBXFadeStream *stream;
3768
g_rec_mutex_lock (&player->priv->stream_list_lock);
3769
stream = find_stream_by_state (player, FADING_IN | PLAYING | PAUSED | FADING_OUT_PAUSED | PENDING_REMOVE);
3770
g_rec_mutex_unlock (&player->priv->stream_list_lock);
3772
if (stream == NULL) {
3773
rb_debug ("got seek while no playing streams exist");
3777
stream->seek_target = time;
3778
switch (stream->state) {
3780
rb_debug ("seeking in paused stream %s; target %"
3781
G_GINT64_FORMAT, stream->uri, stream->seek_target);
3782
perform_seek (stream);
3785
case FADING_OUT_PAUSED:
3786
/* don't unblock and relink when the seek is done */
3787
stream->state = SEEKING_PAUSED;
3788
rb_debug ("seeking in pausing stream %s; target %"
3789
G_GINT64_FORMAT, stream->uri, stream->seek_target);
3790
unlink_and_block_stream (stream);
3795
stream->state = SEEKING;
3796
rb_debug ("seeking in playing stream %s; target %"
3797
G_GINT64_FORMAT, stream->uri, stream->seek_target);
3798
perform_seek (stream);
3801
case PENDING_REMOVE:
3802
/* this should only happen when the stream has ended,
3803
* which means we can't wait for the src pad to be blocked
3804
* before we seek. we unlink the stream when it reaches EOS,
3805
* so now we just perform the seek and relink.
3807
rb_debug ("seeking in EOS stream %s; target %"
3808
G_GINT64_FORMAT, stream->uri, stream->seek_target);
3809
stream->state = SEEKING_EOS;
3810
gst_pad_add_probe (stream->src_pad,
3811
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
3812
(GstPadProbeCallback) post_eos_seek_blocked_cb,
3815
perform_seek (stream);
3818
g_assert_not_reached ();
3821
g_object_unref (stream);
3825
rb_player_gst_xfade_get_time (RBPlayer *iplayer)
3828
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3830
get_times_and_stream (player, NULL, &pos, NULL);
3835
need_pad_block (RBPlayerGstXFade *player)
3837
return (player->priv->sink_state == SINK_PLAYING);
3841
rb_player_gst_xfade_add_tee (RBPlayerGstTee *iplayer, GstElement *element)
3843
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3844
if (player->priv->tee == NULL) {
3845
player->priv->waiting_tees = g_list_prepend (player->priv->waiting_tees, element);
3849
return rb_gst_add_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
3853
rb_player_gst_xfade_remove_tee (RBPlayerGstTee *iplayer, GstElement *element)
3855
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3856
if (player->priv->tee == NULL) {
3857
gst_object_ref_sink (element);
3858
player->priv->waiting_tees = g_list_remove (player->priv->waiting_tees, element);
3862
return rb_gst_remove_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
3867
rb_player_gst_xfade_add_filter (RBPlayerGstFilter *iplayer, GstElement *element)
3869
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3870
if (player->priv->filterbin == NULL) {
3871
player->priv->waiting_filters = g_list_prepend (player->priv->waiting_filters, element);
3875
return rb_gst_add_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));
3880
rb_player_gst_xfade_remove_filter (RBPlayerGstFilter *iplayer, GstElement *element)
3882
RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
3883
if (player->priv->filterbin == NULL) {
3884
gst_object_ref_sink (element);
3885
player->priv->waiting_filters = g_list_remove (player->priv->waiting_filters, element);
3889
return rb_gst_remove_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));