~ubuntu-branches/ubuntu/trusty/rhythmbox/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/0001-xfade-fix-playback-over-sftp-with-gstreamer-1.2.patch/backends/gstreamer/rb-player-gst-xfade.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2013-11-15 15:16:05 UTC
  • Revision ID: package-import@ubuntu.com-20131115151605-ntvsvo8isp3c1uom
Tags: 3.0.1-1ubuntu5
* Update Breaks and Replaces from rhythmbox-data to rhythmbox; the apport
  hook moved here in ubuntu3. 
* debian/patches/0001-xfade-fix-playback-over-sftp-with-gstreamer-1.2.patch:
  Cherry-pick patch from upstream to fix playback of remote files with
  GStreamer 1.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 *  Copyright (C) 2006,2010   Jonathan Matthew  <jonathan@d14n.org>
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 
11
 *  GStreamer plugins to be used and distributed together with GStreamer
 
12
 *  and Rhythmbox. This permission is above and beyond the permissions granted
 
13
 *  by the GPL license by which Rhythmbox is covered. If you modify this code
 
14
 *  you may extend this exception to your version of the code, but you are not
 
15
 *  obligated to do so. If you do not wish to do so, delete this exception
 
16
 *  statement from your version.
 
17
 *
 
18
 *  This program is distributed in the hope that it will be useful,
 
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 *  GNU General Public License for more details.
 
22
 *
 
23
 *  You should have received a copy of the GNU General Public License
 
24
 *  along with this program; if not, write to the Free Software
 
25
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 
26
 *
 
27
 */
 
28
 
 
29
/*
 
30
 * GStreamer player backend with crossfading and gaplessness and trees and
 
31
 * flowers and bunnies.
 
32
 */
 
33
 
 
34
/*
 
35
 * basic design:
 
36
 *
 
37
 * we have a single output bin, beginning with an adder.
 
38
 * connected to this are a number of stream bins, consisting of a
 
39
 * source, 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?)
 
42
 *
 
43
 * stream bins only stay connected to the adder while actually playing.
 
44
 * when not playing (prerolling or paused), the stream bin's source pad
 
45
 * is blocked so no data can flow.
 
46
 *
 
47
 * streams go through a number of states:
 
48
 *
 
49
 * when a stream is created (in rb_player_open()), it starts in PREROLLING
 
50
 * state.  from there:
 
51
 *
 
52
 * - rb_player_play():  -> PREROLL_PLAY
 
53
 * - preroll finishes:  -> WAITING
 
54
 *
 
55
 * from WAITING:
 
56
 *
 
57
 * - rb_player_play(), _AFTER_EOS, other stream playing:  -> WAITING_EOS
 
58
 * - rb_player_play(), _CROSSFADE, other stream playing:   -> FADING IN, link to adder, unblock
 
59
 *      + fade out existing stream
 
60
 * - rb_player_play(), _REPLACE, other stream playing:   -> PLAYING, link to adder, unblock
 
61
 *      + stop existing stream
 
62
 * - rb_player_play(), existing stream paused:  -> PLAYING, link to adder, unblock
 
63
 *      + stop existing stream
 
64
 * - rb_player_play(), nothing already playing:  -> PLAYING, link to adder, unblock
 
65
 *
 
66
 * from PREROLL_PLAY:
 
67
 *
 
68
 * - preroll finishes, _AFTER_EOS, other stream playing:  -> WAITING_EOS
 
69
 * - preroll finishes, _CROSSFADE, other stream playing:  -> FADING_IN, link to adder, unblock
 
70
 *      + fade out existing stream
 
71
 * - preroll finishes, _REPLACE, other stream playing:  -> PLAYING, link to adder, unblock
 
72
 *      + stop existing stream
 
73
 * - preroll finishes, existing stream paused:  -> PLAYING, link to adder, unblock
 
74
 *      + stop existing stream
 
75
 * - preroll finishes, nothing already playing:  -> PLAYING, link to adder, unblock
 
76
 *
 
77
 * from WAITING_EOS:
 
78
 *
 
79
 * - EOS received for another stream:  -> PLAYING, link to adder, unblock
 
80
 *
 
81
 * from FADING_IN:
 
82
 *
 
83
 * - fade in completes:  -> PLAYING
 
84
 * - another stream starts fading in:  -> FADING_OUT
 
85
 * - rb_player_pause():  -> PAUSED, block, unlink from adder
 
86
 * - stopped for another stream:  -> PENDING_REMOVE
 
87
 * - rb_player_set_time():  -> SEEKING, block, unlink
 
88
 * - reused for another stream:  -> REUSING; block, unlink
 
89
 *
 
90
 * from PLAYING:
 
91
 *
 
92
 * - rb_player_pause(): -> FADING_OUT_PAUSE, fade out (short fade)
 
93
 * - EOS:  -> PENDING_REMOVE
 
94
 * - another stream starts fading in:  -> FADING_OUT
 
95
 * - stopped for another stream:  -> PENDING_REMOVE
 
96
 * - rb_player_set_time():  -> SEEKING, block, unlink
 
97
 * - reused for another stream:  -> REUSING; block, unlink
 
98
 *
 
99
 * from SEEKING:
 
100
 * - rb_player_pause():  -> SEEKING_PAUSED
 
101
 * - blocked:  perform seek, link, unblock -> PLAYING | FADING_IN
 
102
 *
 
103
 * from SEEKING_PAUSED:
 
104
 * - blocked:  perform seek, -> PAUSED
 
105
 * - rb_player_play():   -> SEEKING
 
106
 *
 
107
 * from PAUSED:
 
108
 *
 
109
 * - rb_player_play():    -> FADING IN, link to adder, unblock (short fade)
 
110
 * - stopped for another stream:  -> PENDING_REMOVE
 
111
 * - rb_player_set_time(): -> perform seek
 
112
 *
 
113
 * from FADING_OUT:
 
114
 *
 
115
 * - fade out finishes:  -> PENDING_REMOVE
 
116
 * - EOS:  -> PENDING_REMOVE
 
117
 * - reused for another stream:  -> REUSING; block, unlink
 
118
 *
 
119
 * from FADING_OUT_PAUSED:
 
120
 *
 
121
 * - fade out finishes: -> SEEKING_PAUSED, block, unlink
 
122
 * - EOS: -> PENDING_REMOVE
 
123
 * - reused for another stream: -> REUSING, block, unlink
 
124
 * - rb_player_set_time():  -> SEEKING_PAUSED, block, unlink
 
125
 *
 
126
 * from PENDING_REMOVE:
 
127
 * - rb_player_set_time():  -> block, seek, -> SEEKING_EOS
 
128
 * - reap_streams idle handler called:  -> unlink from adder, stream destroyed
 
129
 *
 
130
 * from SEEKING_EOS:
 
131
 * - block completes -> link, unblock, -> PLAYING
 
132
 * - rb_player_pause() -> SEEKING_PAUSED
 
133
 *
 
134
 * from REUSING:
 
135
 *  - EOS: emit reuse-stream, -> PLAYING
 
136
 *  - rb_player_play(): -> block, unlink
 
137
 *  - blocked:  emit reuse-stream, link -> PLAYING
 
138
 */
 
139
 
 
140
#include "config.h"
 
141
#include <math.h>
 
142
 
 
143
#include <glib/gi18n.h>
 
144
#include <gst/gst.h>
 
145
#include <gst/controller/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>
 
150
 
 
151
#include "rb-player.h"
 
152
#include "rb-player-gst-xfade.h"
 
153
#include "rb-debug.h"
 
154
#include "rb-file-helpers.h"
 
155
#include "rb-util.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"
 
160
 
 
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);
 
166
 
 
167
static gboolean rb_player_gst_xfade_open (RBPlayer *player,
 
168
                                          const char *uri,
 
169
                                          gpointer stream_data,
 
170
                                          GDestroyNotify stream_data_destroy,
 
171
                                          GError **error);
 
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);
 
186
 
 
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);
 
191
 
 
192
GType rb_xfade_stream_get_type (void);
 
193
GType rb_xfade_stream_bin_get_type (void);
 
194
 
 
195
G_DEFINE_TYPE_WITH_CODE(RBPlayerGstXFade, rb_player_gst_xfade, G_TYPE_OBJECT,
 
196
                        G_IMPLEMENT_INTERFACE(RB_TYPE_PLAYER,
 
197
                                              rb_player_init)
 
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))
 
202
 
 
203
#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYER_GST_XFADE, RBPlayerGstXFadePrivate))
 
204
 
 
205
#define RB_PLAYER_GST_XFADE_TICK_HZ 5
 
206
 
 
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"
 
212
 
 
213
#define PAUSE_FADE_LENGTH       (GST_SECOND / 2)
 
214
 
 
215
enum
 
216
{
 
217
        PROP_0,
 
218
        PROP_BUS
 
219
};
 
220
 
 
221
enum
 
222
{
 
223
        PREPARE_SOURCE,
 
224
        CAN_REUSE_STREAM,
 
225
        REUSE_STREAM,
 
226
        MISSING_PLUGINS,
 
227
        GET_STREAM_FILTERS,
 
228
        LAST_SIGNAL
 
229
};
 
230
 
 
231
/* copied from gsturidecodebin.c:stream_uris */
 
232
static const char *stream_schemes[] = {
 
233
        "http", "https", "mms", "mmsh", "mmsu", "mmst", "ssh", "ftp", "sftp"
 
234
};
 
235
 
 
236
static guint signals[LAST_SIGNAL] = { 0 };
 
237
 
 
238
struct _RBPlayerGstXFadePrivate
 
239
{
 
240
        /* probably don't need to store pointers to these either */
 
241
        GstElement *pipeline;
 
242
        GstElement *outputbin;
 
243
        GstElement *silencebin;
 
244
        GstElement *adder;
 
245
        GstElement *capsfilter;
 
246
        GstElement *volume;
 
247
        GstElement *sink;
 
248
        GstElement *tee;
 
249
        GstElement *filterbin;
 
250
        GstElement *filteridentity;
 
251
        GstElement *filterconvert;
 
252
        GstElement *volume_handler;
 
253
        enum {
 
254
                SINK_NULL,
 
255
                SINK_STOPPED,
 
256
                SINK_PLAYING
 
257
        } sink_state;
 
258
        GRecMutex sink_lock;
 
259
 
 
260
        GList *waiting_tees;
 
261
        GList *waiting_filters;
 
262
 
 
263
        GRecMutex stream_list_lock;
 
264
        GList *streams;
 
265
        gint linked_streams;
 
266
 
 
267
        int volume_changed;
 
268
        int volume_applied;
 
269
        float cur_volume;
 
270
 
 
271
        guint tick_timeout_id;
 
272
 
 
273
        guint stream_reap_id;
 
274
        guint stop_sink_id;
 
275
        guint bus_watch_id;
 
276
};
 
277
 
 
278
 
 
279
/* these aren't actually used to construct bitmasks,
 
280
 * but we search the list that way.
 
281
 */
 
282
typedef enum
 
283
{
 
284
        /* stable states */
 
285
        WAITING = 1,
 
286
        PLAYING = 2,
 
287
        PAUSED = 4,
 
288
 
 
289
        /* transition states */
 
290
        REUSING = 8,
 
291
        PREROLLING = 16,
 
292
        PREROLL_PLAY = 32,
 
293
        FADING_IN = 64,
 
294
        SEEKING = 128,
 
295
        SEEKING_PAUSED = 256,
 
296
        SEEKING_EOS = 512, 
 
297
        WAITING_EOS = 1024,
 
298
        FADING_OUT = 2048,
 
299
        FADING_OUT_PAUSED = 4096,
 
300
        PENDING_REMOVE = 8192
 
301
} StreamState;
 
302
 
 
303
typedef struct {
 
304
        GstBinClass bin_class;
 
305
} RBXFadeStreamClass;
 
306
 
 
307
 
 
308
typedef struct
 
309
{
 
310
        GstBin parent;
 
311
        RBPlayerGstXFade *player;
 
312
 
 
313
        GMutex lock;
 
314
 
 
315
        char *uri;
 
316
        gpointer stream_data;
 
317
        GDestroyNotify stream_data_destroy;
 
318
 
 
319
        /* stream reuse data */
 
320
        char *new_uri;
 
321
        gpointer new_stream_data;
 
322
        GDestroyNotify new_stream_data_destroy;
 
323
 
 
324
        /* probably don't need to store pointers to all of these.. */
 
325
        GstElement *decoder;
 
326
        GstElement *volume;
 
327
        GstElement *audioconvert;
 
328
        GstElement *audioresample;
 
329
        GstElement *capsfilter;
 
330
        GstElement *preroll;
 
331
        GstElement *identity;
 
332
        gboolean decoder_linked;
 
333
        gboolean emitted_playing;
 
334
        gboolean emitted_fake_playing;
 
335
 
 
336
        GstPad *decoder_pad;
 
337
        GstPad *src_pad;
 
338
        GstPad *ghost_pad;
 
339
        GstPad *adder_pad;
 
340
        gboolean src_blocked;
 
341
        gboolean needs_unlink;
 
342
        GstClockTime base_time;
 
343
 
 
344
        gint64 seek_target;
 
345
 
 
346
        GstTimedValueControlSource *fader;
 
347
        StreamState state;
 
348
        RBPlayerPlayType play_type;
 
349
        gint64 crossfade;
 
350
        gboolean fading;
 
351
        gboolean starting_eos;
 
352
        gboolean use_buffering;
 
353
 
 
354
        gulong adjust_probe_id;
 
355
        gulong block_probe_id;
 
356
 
 
357
        double fade_end;
 
358
 
 
359
        gboolean emitted_error;
 
360
        gulong error_idle_id;
 
361
        GError *error;
 
362
 
 
363
        GSList *missing_plugins;
 
364
        gulong  emit_missing_plugins_id;
 
365
 
 
366
        GList *tags;
 
367
} RBXFadeStream;
 
368
 
 
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))
 
372
 
 
373
static void adjust_stream_base_time (RBXFadeStream *stream);
 
374
static gboolean actually_start_stream (RBXFadeStream *stream, GError **error);
 
375
 
 
376
static void rb_xfade_stream_class_init (RBXFadeStreamClass *klass);
 
377
 
 
378
G_DEFINE_TYPE(RBXFadeStream, rb_xfade_stream, GST_TYPE_BIN)
 
379
 
 
380
static gboolean
 
381
rb_xfade_stream_send_event (GstElement *element, GstEvent *event)
 
382
{
 
383
        GstPad *pad;
 
384
        GstPad *ghost_pad;
 
385
        gboolean ret;
 
386
 
 
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));
 
390
 
 
391
        ret = gst_element_send_event (GST_PAD_PARENT (pad), event);
 
392
 
 
393
        gst_object_unref (pad);
 
394
        gst_object_unref (ghost_pad);
 
395
 
 
396
        return ret;
 
397
}
 
398
 
 
399
static void
 
400
rb_xfade_stream_init (RBXFadeStream *stream)
 
401
{
 
402
        g_mutex_init (&stream->lock);
 
403
}
 
404
 
 
405
static void
 
406
rb_xfade_stream_dispose_stream_data (RBXFadeStream *stream)
 
407
{
 
408
        if (stream->stream_data && stream->stream_data_destroy) {
 
409
                stream->stream_data_destroy (stream->stream_data);
 
410
        }
 
411
        stream->stream_data = NULL;
 
412
        stream->stream_data_destroy = NULL;
 
413
}
 
414
 
 
415
static void
 
416
rb_xfade_stream_dispose (GObject *object)
 
417
{
 
418
        RBXFadeStream *sd = RB_XFADE_STREAM (object);
 
419
 
 
420
        rb_debug ("disposing stream %s", sd->uri);
 
421
 
 
422
        if (sd->decoder != NULL) {
 
423
                gst_object_unref (sd->decoder);
 
424
                sd->decoder = NULL;
 
425
        }
 
426
 
 
427
        if (sd->volume != NULL) {
 
428
                gst_object_unref (sd->volume);
 
429
                sd->volume = NULL;
 
430
        }
 
431
 
 
432
        if (sd->fader != NULL) {
 
433
                gst_object_unref (sd->fader);
 
434
                sd->fader = NULL;
 
435
        }
 
436
 
 
437
        if (sd->audioconvert != NULL) {
 
438
                gst_object_unref (sd->audioconvert);
 
439
                sd->audioconvert = NULL;
 
440
        }
 
441
 
 
442
        if (sd->audioresample != NULL) {
 
443
                gst_object_unref (sd->audioresample);
 
444
                sd->audioresample = NULL;
 
445
        }
 
446
 
 
447
        if (sd->player != NULL) {
 
448
                g_object_unref (sd->player);
 
449
                sd->player = NULL;
 
450
        }
 
451
 
 
452
        if (sd->tags != NULL) {
 
453
                rb_list_destroy_free (sd->tags, (GDestroyNotify) gst_tag_list_unref);
 
454
                sd->tags = NULL;
 
455
        }
 
456
 
 
457
        rb_xfade_stream_dispose_stream_data (sd);
 
458
 
 
459
        G_OBJECT_CLASS (rb_xfade_stream_parent_class)->dispose (object);
 
460
}
 
461
 
 
462
static void
 
463
rb_xfade_stream_finalize (GObject *object)
 
464
{
 
465
        RBXFadeStream *sd = RB_XFADE_STREAM (object);
 
466
        
 
467
        g_free (sd->uri);
 
468
 
 
469
        if (sd->error != NULL) {
 
470
                g_error_free (sd->error);
 
471
        }
 
472
 
 
473
        G_OBJECT_CLASS (rb_xfade_stream_parent_class)->finalize (object);
 
474
}
 
475
 
 
476
static void
 
477
rb_xfade_stream_class_init (RBXFadeStreamClass *klass)
 
478
{
 
479
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
480
        GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
481
 
 
482
        object_class->dispose = rb_xfade_stream_dispose;
 
483
        object_class->finalize = rb_xfade_stream_finalize;
 
484
 
 
485
        element_class->send_event = rb_xfade_stream_send_event;
 
486
}
 
487
 
 
488
/* caller must hold stream list lock */
 
489
static void
 
490
dump_stream_list (RBPlayerGstXFade *player)
 
491
{
 
492
        GList *l;
 
493
        if (player->priv->streams == NULL) {
 
494
                rb_debug ("stream list is empty");
 
495
        } else {
 
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;
 
504
 
 
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;
 
515
 
 
516
                        case PENDING_REMOVE:    statename = "pending remove";   break;
 
517
                        }
 
518
 
 
519
                        rb_debug ("[%s] %s", statename, stream->uri);
 
520
                }
 
521
        }
 
522
}
 
523
 
 
524
/* caller must hold stream list lock */
 
525
static RBXFadeStream *
 
526
find_stream_by_uri (RBPlayerGstXFade *player, const char *uri)
 
527
{
 
528
        GList *i;
 
529
        if (uri == NULL)
 
530
                return NULL;
 
531
 
 
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);
 
536
        }
 
537
        return NULL;
 
538
}
 
539
 
 
540
/* caller must hold stream list lock */
 
541
static RBXFadeStream *
 
542
find_stream_by_element (RBPlayerGstXFade *player, GstElement *element)
 
543
{
 
544
        GList *i;
 
545
 
 
546
        for (i = player->priv->streams; i != NULL; i = i->next) {
 
547
                RBXFadeStream *stream;
 
548
                GstElement *e;
 
549
 
 
550
                stream = (RBXFadeStream *)i->data;
 
551
                e = element;
 
552
                while (e != NULL) {
 
553
                        if (e == GST_ELEMENT (stream))
 
554
                                return g_object_ref (stream);
 
555
 
 
556
                        e = GST_ELEMENT_PARENT (e);
 
557
                }
 
558
        }
 
559
 
 
560
        return NULL;
 
561
}
 
562
 
 
563
/* caller must hold stream list lock */
 
564
static RBXFadeStream *
 
565
find_stream_by_state (RBPlayerGstXFade *player, gint state_mask)
 
566
{
 
567
        GList *i;
 
568
 
 
569
        for (i = player->priv->streams; i != NULL; i = i->next) {
 
570
                RBXFadeStream *stream;
 
571
 
 
572
                stream = (RBXFadeStream *)i->data;
 
573
                if ((stream->state & state_mask) != 0) {
 
574
                        return g_object_ref (stream);
 
575
                }
 
576
        }
 
577
 
 
578
        return NULL;
 
579
}
 
580
 
 
581
static RBXFadeStream *
 
582
find_stream_for_message (RBPlayerGstXFade *player, GstMessage *message)
 
583
{
 
584
        GstObject *message_src;
 
585
        RBXFadeStream *stream;
 
586
 
 
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);
 
591
        }
 
592
        stream = find_stream_by_element (player, GST_ELEMENT (message_src));
 
593
        if (stream != NULL)
 
594
                return stream;
 
595
 
 
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.
 
598
         */
 
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);
 
601
        }
 
602
 
 
603
        return NULL;
 
604
}
 
605
 
 
606
static void
 
607
rb_player_gst_xfade_get_property (GObject *object,
 
608
                                  guint prop_id,
 
609
                                  GValue *value,
 
610
                                  GParamSpec *pspec)
 
611
{
 
612
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);
 
613
 
 
614
        switch (prop_id) {
 
615
        case PROP_BUS:
 
616
                if (player->priv->pipeline) {
 
617
                        GstBus *bus;
 
618
                        bus = gst_element_get_bus (player->priv->pipeline);
 
619
                        g_value_set_object (value, bus);
 
620
                        gst_object_unref (bus);
 
621
                }
 
622
                break;
 
623
        default:
 
624
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
625
                break;
 
626
        }
 
627
}
 
628
 
 
629
static void
 
630
rb_player_gst_xfade_set_property (GObject *object,
 
631
                                  guint prop_id,
 
632
                                  const GValue *value,
 
633
                                  GParamSpec *pspec)
 
634
{
 
635
        /*RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (object);*/
 
636
 
 
637
        switch (prop_id) {
 
638
        default:
 
639
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
640
                break;
 
641
        }
 
642
}
 
643
 
 
644
static void
 
645
rb_player_gst_xfade_class_init (RBPlayerGstXFadeClass *klass)
 
646
{
 
647
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
648
 
 
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;
 
653
 
 
654
        g_object_class_install_property (object_class,
 
655
                                         PROP_BUS,
 
656
                                         g_param_spec_object ("bus",
 
657
                                                              "bus",
 
658
                                                              "GStreamer message bus",
 
659
                                                              GST_TYPE_BUS,
 
660
                                                              G_PARAM_READABLE));
 
661
 
 
662
        signals[PREPARE_SOURCE] =
 
663
                g_signal_new ("prepare-source",
 
664
                              G_OBJECT_CLASS_TYPE (object_class),
 
665
                              G_SIGNAL_RUN_LAST,
 
666
                              G_STRUCT_OFFSET (RBPlayerGstXFadeClass, prepare_source),
 
667
                              NULL, NULL,
 
668
                              rb_marshal_VOID__STRING_OBJECT,
 
669
                              G_TYPE_NONE,
 
670
                              2,
 
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),
 
675
                              G_SIGNAL_RUN_LAST,
 
676
                              G_STRUCT_OFFSET (RBPlayerGstXFadeClass, can_reuse_stream),
 
677
                              NULL, NULL,
 
678
                              rb_marshal_BOOLEAN__STRING_STRING_OBJECT,
 
679
                              G_TYPE_BOOLEAN,
 
680
                              3,
 
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),
 
685
                              G_SIGNAL_RUN_LAST,
 
686
                              G_STRUCT_OFFSET (RBPlayerGstXFadeClass, reuse_stream),
 
687
                              NULL, NULL,
 
688
                              rb_marshal_VOID__STRING_STRING_OBJECT,
 
689
                              G_TYPE_NONE,
 
690
                              3,
 
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),
 
695
                              G_SIGNAL_RUN_LAST,
 
696
                              0,        /* no point handling this internally */
 
697
                              NULL, NULL,
 
698
                              rb_marshal_VOID__POINTER_POINTER_POINTER,
 
699
                              G_TYPE_NONE,
 
700
                              3,
 
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),
 
705
                              G_SIGNAL_RUN_LAST,
 
706
                              0,
 
707
                              rb_signal_accumulator_value_array, NULL,
 
708
                              rb_marshal_BOXED__STRING,
 
709
                              G_TYPE_ARRAY,
 
710
                              1,
 
711
                              G_TYPE_STRING);
 
712
 
 
713
        g_type_class_add_private (klass, sizeof (RBPlayerGstXFadePrivate));
 
714
}
 
715
 
 
716
static void
 
717
rb_player_init (RBPlayerIface *iface)
 
718
{
 
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;
 
731
}
 
732
 
 
733
static void
 
734
rb_player_gst_tee_init (RBPlayerGstTeeIface *iface)
 
735
{
 
736
        iface->add_tee = rb_player_gst_xfade_add_tee;
 
737
        iface->remove_tee = rb_player_gst_xfade_remove_tee;
 
738
}
 
739
 
 
740
static void
 
741
rb_player_gst_filter_init (RBPlayerGstFilterIface *iface)
 
742
{
 
743
        iface->add_filter = rb_player_gst_xfade_add_filter;
 
744
        iface->remove_filter = rb_player_gst_xfade_remove_filter;
 
745
}
 
746
 
 
747
 
 
748
static void
 
749
rb_player_gst_xfade_init (RBPlayerGstXFade *player)
 
750
{
 
751
        player->priv = GET_PRIVATE (player);
 
752
 
 
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;
 
756
}
 
757
 
 
758
static void
 
759
rb_player_gst_xfade_dispose (GObject *object)
 
760
{
 
761
        RBPlayerGstXFade *player;
 
762
        GList *l;
 
763
 
 
764
        g_return_if_fail (RB_IS_PLAYER_GST_XFADE (object));
 
765
        player = RB_PLAYER_GST_XFADE (object);
 
766
 
 
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;
 
771
 
 
772
                /* unlink instead? */
 
773
                gst_element_set_state (GST_ELEMENT (stream), GST_STATE_NULL);
 
774
 
 
775
                g_object_unref (stream);
 
776
        }
 
777
        g_list_free (player->priv->streams);
 
778
        player->priv->streams = NULL;
 
779
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
780
 
 
781
        if (player->priv->volume_handler) {
 
782
                g_object_unref (player->priv->volume_handler);
 
783
                player->priv->volume_handler = NULL;
 
784
        }
 
785
 
 
786
        g_rec_mutex_lock (&player->priv->sink_lock);
 
787
        stop_sink (player);
 
788
        g_rec_mutex_unlock (&player->priv->sink_lock);
 
789
 
 
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;
 
795
        }
 
796
 
 
797
        G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->dispose (object);
 
798
}
 
799
 
 
800
static void
 
801
rb_player_gst_xfade_finalize (GObject *object)
 
802
{
 
803
        RBPlayerGstXFade *player;
 
804
 
 
805
        player = RB_PLAYER_GST_XFADE (object);
 
806
 
 
807
        if (player->priv->waiting_tees) {
 
808
                g_list_foreach (player->priv->waiting_tees, (GFunc)gst_object_ref_sink, NULL);
 
809
        }
 
810
        g_list_free (player->priv->waiting_tees);
 
811
 
 
812
        if (player->priv->waiting_filters) {
 
813
                g_list_foreach (player->priv->waiting_filters, (GFunc)gst_object_ref_sink, NULL);
 
814
        }
 
815
        g_list_free (player->priv->waiting_filters);
 
816
 
 
817
        G_OBJECT_CLASS (rb_player_gst_xfade_parent_class)->finalize (object);
 
818
}
 
819
 
 
820
RBPlayer *
 
821
rb_player_gst_xfade_new (GError **error)
 
822
{
 
823
        RBPlayer *mp;
 
824
 
 
825
        mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER_GST_XFADE, NULL, NULL));
 
826
 
 
827
        return mp;
 
828
}
 
829
 
 
830
static gboolean
 
831
emit_stream_error_cb (RBXFadeStream *stream)
 
832
{
 
833
        stream->error_idle_id = 0;
 
834
        _rb_player_emit_error (RB_PLAYER (stream->player),
 
835
                               stream->stream_data,
 
836
                               stream->error);
 
837
        g_error_free (stream->error);
 
838
        stream->error = NULL;
 
839
 
 
840
        return FALSE;
 
841
}
 
842
 
 
843
static void
 
844
emit_stream_error (RBXFadeStream *stream, GError *error)
 
845
{
 
846
        if (stream->error_idle_id != 0) {
 
847
                g_error_free (error);
 
848
        } else {
 
849
                stream->error = error;
 
850
                stream->error_idle_id = g_idle_add ((GSourceFunc) emit_stream_error_cb,
 
851
                                                    stream);
 
852
        }
 
853
}
 
854
 
 
855
static void
 
856
post_stream_playing_message (RBXFadeStream *stream, gboolean fake)
 
857
{
 
858
        GstMessage *msg;
 
859
        GstStructure *s;
 
860
 
 
861
        if (stream->emitted_playing) {
 
862
                return;
 
863
        }
 
864
 
 
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);
 
869
 
 
870
        if (fake == FALSE) {
 
871
                stream->emitted_playing = TRUE;
 
872
        } else {
 
873
                stream->emitted_fake_playing = TRUE;
 
874
        }
 
875
}
 
876
 
 
877
static GstPadProbeReturn
 
878
adjust_base_time_probe_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
879
{
 
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;
 
885
}
 
886
 
 
887
/* updates a stream's base time so its position is reported correctly */
 
888
static void
 
889
adjust_stream_base_time (RBXFadeStream *stream)
 
890
{
 
891
        gint64 output_pos = -1;
 
892
        gint64 stream_pos = -1;
 
893
 
 
894
        if (stream->adder_pad == NULL) {
 
895
                rb_debug ("stream isn't linked, can't adjust base time");
 
896
                return;
 
897
        }
 
898
 
 
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;
 
902
        }
 
903
 
 
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;
 
912
 
 
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;
 
917
                }
 
918
        } else {
 
919
                rb_debug ("unable to adjust base time as position query failed");
 
920
 
 
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,
 
927
                                                   stream,
 
928
                                                   NULL);
 
929
                }
 
930
        }
 
931
}
 
932
 
 
933
/* called on a streaming thread when the volume level for a stream changes. */
 
934
static void
 
935
volume_changed_cb (GObject *object, GParamSpec *pspec, RBPlayerGstXFade *player)
 
936
{
 
937
        RBXFadeStream *stream;
 
938
        gdouble vol;
 
939
        char *message = NULL;
 
940
 
 
941
        /* post app messages on the bus when fades complete.
 
942
         * our bus callback will handle them on the main thread.
 
943
         */
 
944
 
 
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);
 
948
 
 
949
        if (stream == NULL) {
 
950
                rb_debug ("got volume change for unknown stream");
 
951
                return;
 
952
        }
 
953
 
 
954
        g_mutex_lock (&stream->lock);
 
955
 
 
956
        /* check if the fade is complete */
 
957
        g_object_get (stream->volume, "volume", &vol, NULL);
 
958
        switch (stream->state) {
 
959
        case FADING_IN:
 
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;
 
965
                        
 
966
                /*} else {
 
967
                        rb_debug ("fading %s in: %f", stream->uri, (float)vol);*/
 
968
                }
 
969
                break;
 
970
        case FADING_OUT:
 
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;
 
977
                        }
 
978
                } else {
 
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)
 
983
                         */
 
984
                        gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
 
985
                }
 
986
                break;
 
987
        default:
 
988
                /*rb_debug ("unexpectedly got a volume change for stream %s to %f (not fading)", stream->uri, (float)vol);*/
 
989
                break;
 
990
        }
 
991
        
 
992
        g_mutex_unlock (&stream->lock);
 
993
 
 
994
        if (message != NULL) {
 
995
                GstMessage *msg;
 
996
                GstStructure *s;
 
997
 
 
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);
 
1002
        }
 
1003
 
 
1004
        g_object_unref (stream);
 
1005
}
 
1006
 
 
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
 
1010
 * is done.
 
1011
 */
 
1012
static void
 
1013
start_stream_fade (RBXFadeStream *stream, double start, double end, gint64 time)
 
1014
{
 
1015
        gint64 pos = -1;
 
1016
 
 
1017
        /* hmm, can we take the stream lock safely here?  probably should.. */
 
1018
 
 
1019
        gst_element_query_position (stream->volume, GST_FORMAT_TIME, &pos);
 
1020
        if (pos < 0) {
 
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.
 
1026
                 */
 
1027
                pos = 100000;
 
1028
        }
 
1029
 
 
1030
        rb_debug ("fading stream %s: [%f, %" G_GINT64_FORMAT "] to [%f, %" G_GINT64_FORMAT "]",
 
1031
                  stream->uri,
 
1032
                  (float)start, pos,
 
1033
                  (float)end, pos + time);
 
1034
 
 
1035
        g_signal_handlers_block_by_func (stream->volume, volume_changed_cb, stream->player);
 
1036
 
 
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);
 
1040
 
 
1041
        gst_timed_value_control_source_unset_all (stream->fader);
 
1042
 
 
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");
 
1045
        }
 
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");
 
1048
        }
 
1049
 
 
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");
 
1052
        }
 
1053
 
 
1054
        g_signal_handlers_unblock_by_func (stream->volume, volume_changed_cb, stream->player);
 
1055
 
 
1056
        stream->fading = TRUE;
 
1057
 
 
1058
        /* tiny hack:  if the controlled element is in passthrough mode, the
 
1059
         * controller won't get updated.
 
1060
         */
 
1061
        gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (stream->volume), FALSE);
 
1062
}
 
1063
 
 
1064
 
 
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
 
1069
 */
 
1070
static gboolean
 
1071
link_and_unblock_stream (RBXFadeStream *stream, GError **error)
 
1072
{
 
1073
        GstPadLinkReturn plr;
 
1074
        GstStateChangeReturn scr;
 
1075
        RBPlayerGstXFade *player = stream->player;
 
1076
        gboolean result;
 
1077
        
 
1078
        if (start_sink (player, error) == FALSE) {
 
1079
                rb_debug ("sink didn't start, so we're not going to link the stream");
 
1080
                return FALSE;
 
1081
        }
 
1082
 
 
1083
        if (stream->adder_pad != NULL) {
 
1084
                rb_debug ("stream %s is already linked", stream->uri);
 
1085
                return TRUE;
 
1086
        }
 
1087
        stream->needs_unlink = FALSE;
 
1088
 
 
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));
 
1092
 
 
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");
 
1097
                g_set_error (error,
 
1098
                             RB_PLAYER_ERROR,
 
1099
                             RB_PLAYER_ERROR_GENERAL,
 
1100
                             _("Failed to link new stream into GStreamer pipeline"));
 
1101
                return FALSE;
 
1102
        }
 
1103
 
 
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;
 
1108
 
 
1109
                /* this error message kind of sucks */
 
1110
                rb_debug ("linking stream pad to adder pad failed: %d", plr);
 
1111
                g_set_error (error,
 
1112
                             RB_PLAYER_ERROR,
 
1113
                             RB_PLAYER_ERROR_GENERAL,
 
1114
                             _("Failed to link new stream into GStreamer pipeline"));
 
1115
                return FALSE;
 
1116
        }
 
1117
 
 
1118
 
 
1119
        g_atomic_int_inc (&player->priv->linked_streams);
 
1120
        rb_debug ("now have %d linked streams", player->priv->linked_streams);
 
1121
 
 
1122
        result = TRUE;
 
1123
        g_mutex_lock (&stream->lock);
 
1124
        if (stream->src_blocked) {
 
1125
                GstStateChangeReturn state_ret;
 
1126
 
 
1127
                gst_pad_remove_probe (stream->src_pad, stream->block_probe_id);
 
1128
                stream->block_probe_id = 0;
 
1129
 
 
1130
                rb_debug ("stream %s is unblocked -> FADING_IN | PLAYING", stream->uri);
 
1131
                stream->src_blocked = FALSE;
 
1132
                if (stream->fading)
 
1133
                        stream->state = FADING_IN;
 
1134
                else
 
1135
                        stream->state = PLAYING;
 
1136
                
 
1137
                adjust_stream_base_time (stream);
 
1138
 
 
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));
 
1143
 
 
1144
                post_stream_playing_message (stream, FALSE);
 
1145
        } else {
 
1146
                rb_debug ("??? stream %s is already unblocked -> PLAYING", stream->uri);
 
1147
                stream->state = PLAYING;
 
1148
                adjust_stream_base_time (stream);
 
1149
 
 
1150
                scr = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PLAYING);
 
1151
 
 
1152
                post_stream_playing_message (stream, FALSE);
 
1153
 
 
1154
                if (scr == GST_STATE_CHANGE_FAILURE) {
 
1155
                        g_set_error (error,
 
1156
                                     RB_PLAYER_ERROR,
 
1157
                                     RB_PLAYER_ERROR_GENERAL,
 
1158
                                     _("Failed to start new stream"));
 
1159
                        result = FALSE;
 
1160
                }
 
1161
        }
 
1162
        g_mutex_unlock (&stream->lock);
 
1163
        return result;
 
1164
}
 
1165
 
 
1166
/*
 
1167
 * reuses a stream.  the stream reuse signal is handled by some
 
1168
 * external code somewhere.
 
1169
 */
 
1170
static void
 
1171
reuse_stream (RBXFadeStream *stream)
 
1172
{
 
1173
        g_signal_emit (stream->player,
 
1174
                       signals[REUSE_STREAM], 0,
 
1175
                       stream->new_uri, stream->uri, GST_ELEMENT (stream));
 
1176
 
 
1177
        /* replace URI and stream data */
 
1178
        g_free (stream->uri);
 
1179
        stream->uri = stream->new_uri;
 
1180
 
 
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;
 
1184
 
 
1185
        stream->new_uri = NULL;
 
1186
        stream->new_stream_data = NULL;
 
1187
        stream->new_stream_data_destroy = NULL;
 
1188
 
 
1189
        stream->emitted_playing = FALSE;
 
1190
}
 
1191
 
 
1192
 
 
1193
/*
 
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.
 
1197
 */
 
1198
static void
 
1199
perform_seek (RBXFadeStream *stream)
 
1200
{
 
1201
        GstEvent *event;
 
1202
 
 
1203
        rb_debug ("sending seek event..");
 
1204
 
 
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);
 
1210
 
 
1211
        g_mutex_lock (&stream->lock);
 
1212
        switch (stream->state) {
 
1213
        case SEEKING:
 
1214
                stream->state = PLAYING;
 
1215
                break;
 
1216
        case SEEKING_PAUSED:
 
1217
                rb_debug ("leaving paused stream %s unlinked", stream->uri);
 
1218
                stream->state = PAUSED;
 
1219
                break;
 
1220
        case SEEKING_EOS:
 
1221
                rb_debug ("waiting for pad block to complete for %s before unlinking", stream->uri);
 
1222
                break;
 
1223
        default:
 
1224
                break;
 
1225
        }
 
1226
 
 
1227
        g_mutex_unlock (&stream->lock);
 
1228
}
 
1229
 
 
1230
static gboolean
 
1231
perform_seek_idle (RBXFadeStream *stream)
 
1232
{
 
1233
        perform_seek (stream);
 
1234
        g_object_unref (stream);
 
1235
        return FALSE;
 
1236
}
 
1237
 
 
1238
/*
 
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.
 
1242
 */
 
1243
static GstPadProbeReturn
 
1244
post_eos_seek_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
1245
{
 
1246
        GError *error = NULL;
 
1247
 
 
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);
 
1252
 
 
1253
        if (link_and_unblock_stream (stream, &error) == FALSE) {
 
1254
                emit_stream_error (stream, error);
 
1255
        }
 
1256
 
 
1257
 
 
1258
        return GST_PAD_PROBE_REMOVE;
 
1259
}
 
1260
 
 
1261
/*
 
1262
 * called when a src pad for a stream is blocked during reuse.
 
1263
 * we don't need to do anything here.
 
1264
 */
 
1265
static GstPadProbeReturn
 
1266
unlink_reuse_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
1267
{
 
1268
        return GST_PAD_PROBE_OK;
 
1269
}
 
1270
 
 
1271
static void
 
1272
unlink_reuse_relink (RBPlayerGstXFade *player, RBXFadeStream *stream)
 
1273
{
 
1274
        GError *error = NULL;
 
1275
 
 
1276
        g_mutex_lock (&stream->lock);
 
1277
 
 
1278
        if (stream->adder_pad == NULL) {
 
1279
                rb_debug ("stream %s doesn't need to be unlinked.. weird.", stream->uri);
 
1280
        } else {
 
1281
                rb_debug ("unlinking stream %s for reuse", stream->uri);
 
1282
 
 
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);
 
1285
                }
 
1286
 
 
1287
                gst_element_release_request_pad (player->priv->adder, stream->adder_pad);
 
1288
                stream->adder_pad = NULL;
 
1289
 
 
1290
                (void) g_atomic_int_dec_and_test (&player->priv->linked_streams);
 
1291
                rb_debug ("%d linked streams left", player->priv->linked_streams);
 
1292
        }
 
1293
 
 
1294
        stream->needs_unlink = FALSE;
 
1295
        stream->emitted_playing = FALSE;
 
1296
 
 
1297
        g_mutex_unlock (&stream->lock);
 
1298
 
 
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
 
1301
         */
 
1302
        gst_pad_add_probe (stream->src_pad,
 
1303
                           GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
 
1304
                           (GstPadProbeCallback) unlink_reuse_blocked_cb,
 
1305
                           stream,
 
1306
                           NULL);
 
1307
        stream->src_blocked = TRUE;
 
1308
 
 
1309
        reuse_stream (stream);
 
1310
        if (link_and_unblock_stream (stream, &error) == FALSE) {
 
1311
                emit_stream_error (stream, error);
 
1312
        }
 
1313
}
 
1314
 
 
1315
/* called when a stream's source pad is blocked, so it can be unlinked
 
1316
 * from the pipeline.
 
1317
 */
 
1318
static GstPadProbeReturn
 
1319
unlink_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
1320
{
 
1321
        int stream_state;
 
1322
        gboolean last;
 
1323
        RBPlayerGstXFade *player;
 
1324
        GError *error = NULL;
 
1325
 
 
1326
        g_mutex_lock (&stream->lock);
 
1327
 
 
1328
        if (stream->needs_unlink == FALSE || stream->adder_pad == NULL) {
 
1329
                g_mutex_unlock (&stream->lock);
 
1330
                return GST_PAD_PROBE_OK;
 
1331
        }
 
1332
 
 
1333
        rb_debug ("stream %s is blocked; unlinking", stream->uri);
 
1334
 
 
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);
 
1337
        }
 
1338
        stream->needs_unlink = FALSE;
 
1339
 
 
1340
        gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
 
1341
        stream->adder_pad = NULL;
 
1342
 
 
1343
        stream->src_blocked = TRUE;
 
1344
        stream->emitted_playing = FALSE;
 
1345
 
 
1346
        stream_state = stream->state;
 
1347
        player = stream->player;
 
1348
 
 
1349
        g_mutex_unlock (&stream->lock);
 
1350
 
 
1351
        /* might want a stream-paused signal here? */
 
1352
 
 
1353
        last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
 
1354
        rb_debug ("%d linked streams left", player->priv->linked_streams);
 
1355
 
 
1356
        /* handle unlinks for seeking and stream reuse */
 
1357
        switch (stream_state) {
 
1358
        case REUSING:
 
1359
                reuse_stream (stream);
 
1360
                if (link_and_unblock_stream (stream, &error) == FALSE) {
 
1361
                        emit_stream_error (stream, error);
 
1362
                }
 
1363
                break;
 
1364
 
 
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.
 
1369
                 */
 
1370
        default:
 
1371
                /* consider pausing the sink if this is the linked last stream */
 
1372
                if (last) {
 
1373
                        maybe_stop_sink (player);
 
1374
                }
 
1375
 
 
1376
                break;
 
1377
        }
 
1378
 
 
1379
        return GST_PAD_PROBE_OK;
 
1380
}
 
1381
 
 
1382
/*
 
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
 
1385
 * stream will play.
 
1386
 */
 
1387
static void
 
1388
unlink_and_block_stream (RBXFadeStream *stream)
 
1389
{
 
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);
 
1394
                return;
 
1395
        }
 
1396
 
 
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);
 
1402
                return;
 
1403
        }
 
1404
 
 
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,
 
1409
                                                            stream,
 
1410
                                                            NULL);
 
1411
        } else {
 
1412
                rb_debug ("already unlinking");
 
1413
        }
 
1414
        g_mutex_unlock (&stream->lock);
 
1415
}
 
1416
 
 
1417
/*
 
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).
 
1421
 *
 
1422
 * must not be called on a streaming thread.
 
1423
 */
 
1424
static void
 
1425
unlink_and_dispose_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
 
1426
{
 
1427
        GstStateChangeReturn sr;
 
1428
        gboolean was_linked = FALSE;
 
1429
        gboolean was_in_pipeline = FALSE;
 
1430
 
 
1431
        /* seems to be too much locking in here.. */
 
1432
 
 
1433
 
 
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);
 
1440
        }
 
1441
        
 
1442
        g_mutex_lock (&stream->lock);
 
1443
 
 
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);
 
1448
                }
 
1449
 
 
1450
                gst_element_release_request_pad (GST_PAD_PARENT (stream->adder_pad), stream->adder_pad);
 
1451
                stream->adder_pad = NULL;
 
1452
 
 
1453
                was_linked = TRUE;
 
1454
        }
 
1455
 
 
1456
        was_in_pipeline = (GST_ELEMENT_PARENT (GST_ELEMENT (stream)) == player->priv->pipeline);
 
1457
        
 
1458
        g_mutex_unlock (&stream->lock);
 
1459
 
 
1460
        if (was_in_pipeline)
 
1461
                gst_bin_remove (GST_BIN (player->priv->pipeline), GST_ELEMENT (stream));
 
1462
 
 
1463
        if (was_linked) {
 
1464
                gboolean last;
 
1465
 
 
1466
                last = g_atomic_int_dec_and_test (&player->priv->linked_streams);
 
1467
                rb_debug ("now have %d linked streams", player->priv->linked_streams);
 
1468
 
 
1469
                if (last) {
 
1470
                        maybe_stop_sink (player);
 
1471
                }
 
1472
        }
 
1473
 
 
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);
 
1478
 
 
1479
        g_object_unref (stream);
 
1480
}
 
1481
 
 
1482
/* idle handler used to clean up finished streams */
 
1483
static gboolean
 
1484
reap_streams (RBPlayerGstXFade *player)
 
1485
{
 
1486
        GList *t;
 
1487
        GList *reap = NULL;
 
1488
 
 
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;
 
1494
 
 
1495
                if (stream->state == PENDING_REMOVE) {
 
1496
                        reap = g_list_prepend (reap, stream);
 
1497
                }
 
1498
        }
 
1499
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
1500
 
 
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);
 
1505
        }
 
1506
        g_list_free (reap);
 
1507
 
 
1508
        return FALSE;
 
1509
}
 
1510
 
 
1511
/* schedules a call to reap_streams */
 
1512
static void
 
1513
schedule_stream_reap (RBPlayerGstXFade *player)
 
1514
{
 
1515
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
1516
 
 
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);
 
1520
        }
 
1521
        
 
1522
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
1523
}
 
1524
 
 
1525
/* emits a tag signal from the player, maybe */
 
1526
static void
 
1527
process_tag (const GstTagList *list, const gchar *tag, RBXFadeStream *stream)
 
1528
{
 
1529
        RBMetaDataField field;
 
1530
        GValue value = {0,};
 
1531
 
 
1532
        /* process embedded images */
 
1533
        if (!g_strcmp0 (tag, GST_TAG_IMAGE) || !g_strcmp0 (tag, GST_TAG_PREVIEW_IMAGE)) {
 
1534
                GdkPixbuf *pixbuf;
 
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,
 
1539
                                               pixbuf);
 
1540
                        g_object_unref (pixbuf);
 
1541
                }
 
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,
 
1546
                                      field,
 
1547
                                      &value);
 
1548
                g_value_unset (&value);
 
1549
        }
 
1550
}
 
1551
 
 
1552
 
 
1553
static gboolean
 
1554
emit_missing_plugins (RBXFadeStream *stream)
 
1555
{
 
1556
        char **details;
 
1557
        char **descriptions;
 
1558
        int count;
 
1559
        GSList *t;
 
1560
        int i;
 
1561
 
 
1562
        stream->emit_missing_plugins_id = 0;
 
1563
        count = g_slist_length (stream->missing_plugins);
 
1564
 
 
1565
        details = g_new0 (char *, count + 1);
 
1566
        descriptions = g_new0 (char *, count + 1);
 
1567
        i = 0;
 
1568
        for (t = stream->missing_plugins; t != NULL; t = t->next) {
 
1569
                GstMessage *msg = GST_MESSAGE (t->data);
 
1570
                char *detail;
 
1571
                char *description;
 
1572
 
 
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);
 
1577
                i++;
 
1578
 
 
1579
                gst_message_unref (msg);
 
1580
        }
 
1581
 
 
1582
        g_signal_emit (stream->player, signals[MISSING_PLUGINS], 0, stream->stream_data, details, descriptions);
 
1583
        g_strfreev (details);
 
1584
        g_strfreev (descriptions);
 
1585
 
 
1586
        g_slist_free (stream->missing_plugins);
 
1587
        stream->missing_plugins = NULL;
 
1588
 
 
1589
        return FALSE;
 
1590
}
 
1591
 
 
1592
 
 
1593
static void
 
1594
rb_player_gst_xfade_handle_missing_plugin_message (RBPlayerGstXFade *player, RBXFadeStream *stream, GstMessage *message)
 
1595
{
 
1596
        if (stream == NULL) {
 
1597
                rb_debug ("got missing-plugin message from unknown stream");
 
1598
                return;
 
1599
        }
 
1600
 
 
1601
        rb_debug ("got missing-plugin message from %s: %s",
 
1602
                  stream->uri,
 
1603
                  gst_missing_plugin_message_get_installer_detail (message));
 
1604
 
 
1605
        /* can only handle missing-plugins while prerolling */
 
1606
        switch (stream->state) {
 
1607
        case PREROLLING:
 
1608
        case PREROLL_PLAY:
 
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));
 
1615
                }
 
1616
 
 
1617
                /* what do we do now?  if we're missing the decoder
 
1618
                 * or something, it'll never preroll..
 
1619
                 */
 
1620
                break;
 
1621
 
 
1622
        default:
 
1623
                rb_debug ("can't process missing-plugin messages for this stream now");
 
1624
                break;
 
1625
        }
 
1626
}
 
1627
 
 
1628
static void
 
1629
start_waiting_eos_streams (RBPlayerGstXFade *player)
 
1630
{
 
1631
        GList *l;
 
1632
        GList *to_start = NULL;
 
1633
 
 
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));
 
1640
                }
 
1641
        }
 
1642
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
1643
 
 
1644
        for (l = to_start; l != NULL; l = l->next) {
 
1645
                RBXFadeStream *pstream = l->data;
 
1646
                GError *error = NULL;
 
1647
 
 
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);
 
1651
                }
 
1652
 
 
1653
                g_object_unref (pstream);
 
1654
        }
 
1655
        g_list_free (to_start);
 
1656
}
 
1657
 
 
1658
/* gstreamer message bus callback */
 
1659
static gboolean
 
1660
rb_player_gst_xfade_bus_cb (GstBus *bus, GstMessage *message, RBPlayerGstXFade *player)
 
1661
{
 
1662
        RBXFadeStream *stream;
 
1663
 
 
1664
        g_return_val_if_fail (player != NULL, FALSE);
 
1665
 
 
1666
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
1667
 
 
1668
        stream = find_stream_for_message (player, message);
 
1669
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
1670
 
 
1671
        switch (GST_MESSAGE_TYPE (message)) {
 
1672
        case GST_MESSAGE_ERROR:
 
1673
        {
 
1674
                char *debug;
 
1675
                GError *error, *sig_error;
 
1676
                int code;
 
1677
                gboolean emit = TRUE;
 
1678
 
 
1679
                gst_message_parse_error (message, &error, &debug);
 
1680
 
 
1681
                if (stream == NULL) {
 
1682
                        rb_debug ("Couldn't find stream for error \"%s\": %s", error->message, debug);
 
1683
                        g_error_free (error);
 
1684
                        g_free (debug);
 
1685
                        break;
 
1686
                }
 
1687
 
 
1688
                /* If we've already got an error, ignore 'internal data flow error'
 
1689
                 * type messages, as they're too generic to be helpful.
 
1690
                 */
 
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);
 
1695
                        emit = FALSE;
 
1696
                }
 
1697
 
 
1698
                code = rb_gst_error_get_error_code (error);
 
1699
 
 
1700
                if (emit) {
 
1701
                        rb_debug ("emitting error %s for stream %s", error->message, stream->uri);
 
1702
                        sig_error = g_error_new_literal (RB_PLAYER_ERROR,
 
1703
                                                         code,
 
1704
                                                         error->message);
 
1705
                        stream->emitted_error = TRUE;
 
1706
                        if (stream->emitted_playing == FALSE) {
 
1707
                                _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
 
1708
                        }
 
1709
                        _rb_player_emit_error (RB_PLAYER (player), stream->stream_data, sig_error);
 
1710
                }
 
1711
 
 
1712
                g_error_free (error);
 
1713
                g_free (debug);
 
1714
                break;
 
1715
        }
 
1716
        case GST_MESSAGE_TAG:
 
1717
                if (stream == NULL) {
 
1718
                        rb_debug ("got tag message for unknown stream");
 
1719
                } else {
 
1720
                        GstTagList *tags;
 
1721
                        gst_message_parse_tag (message, &tags);
 
1722
 
 
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);
 
1727
                        } else {
 
1728
                                stream->tags = g_list_append (stream->tags, tags);
 
1729
                        }
 
1730
                        g_mutex_unlock (&stream->lock);
 
1731
                }
 
1732
                break;
 
1733
 
 
1734
        case GST_MESSAGE_DURATION:
 
1735
                if (stream == NULL) {
 
1736
                        rb_debug ("got duration message for unknown stream");
 
1737
                } else {
 
1738
                        gint64 duration;
 
1739
                        GstFormat format;
 
1740
                        gst_message_parse_duration (message, &format, &duration);
 
1741
                        rb_debug ("got duration %" G_GINT64_FORMAT
 
1742
                            " for stream %s", duration, stream->uri);
 
1743
                }
 
1744
                break;
 
1745
 
 
1746
        case GST_MESSAGE_APPLICATION:
 
1747
        {
 
1748
                /* process fade messages and emit signals for
 
1749
                 * other stuff.
 
1750
                 */
 
1751
                const GstStructure *structure;
 
1752
                const char *name;
 
1753
 
 
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) {
 
1759
                        GList *l;
 
1760
                        GList *t;
 
1761
 
 
1762
                        rb_debug ("got stream playing message for %s", stream->uri);
 
1763
                        _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
 
1764
 
 
1765
                        /* process any buffered tag lists we received while prerolling the stream */
 
1766
                        g_mutex_lock (&stream->lock);
 
1767
                        l = stream->tags;
 
1768
                        stream->tags = NULL;
 
1769
                        g_mutex_unlock (&stream->lock);
 
1770
 
 
1771
                        for (t = l; t != NULL; t = t->next) {
 
1772
                                GstTagList *tags;
 
1773
 
 
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);
 
1778
                        }
 
1779
                        g_list_free (l);
 
1780
 
 
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) {
 
1785
                        case FADING_OUT:
 
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);
 
1792
                                break;
 
1793
 
 
1794
                        case FADING_OUT_PAUSED:
 
1795
                                {
 
1796
                                        /* try to seek back a bit to account for the fade */
 
1797
                                        gint64 pos = -1;
 
1798
 
 
1799
                                        g_mutex_lock (&stream->lock);
 
1800
                                        gst_element_query_position (stream->volume, GST_FORMAT_TIME, &pos);
 
1801
                                        if (pos != -1) {
 
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);
 
1806
                                        } else {
 
1807
                                                stream->state = PAUSED;
 
1808
                                                rb_debug ("got fade-out-done for stream %s -> PAUSED (position query failed)",
 
1809
                                                          stream->uri);
 
1810
                                        }
 
1811
                                        g_mutex_unlock (&stream->lock);
 
1812
                                }
 
1813
                                unlink_and_block_stream (stream);
 
1814
                                break;
 
1815
 
 
1816
                        default:
 
1817
                                g_assert_not_reached ();
 
1818
                        }
 
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.
 
1822
                         */
 
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;
 
1828
 
 
1829
                                unlink_blocked_cb (stream->src_pad, NULL, stream);
 
1830
 
 
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.
 
1834
                                 */
 
1835
                                start_waiting_eos_streams (player);
 
1836
                        } else {
 
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);
 
1839
 
 
1840
                                unlink_reuse_relink (player, stream);
 
1841
                        }
 
1842
 
 
1843
                } else {
 
1844
                        _rb_player_emit_event (RB_PLAYER (player), stream->stream_data, name, NULL);
 
1845
                }
 
1846
 
 
1847
                break;
 
1848
        }
 
1849
        case GST_MESSAGE_BUFFERING:
 
1850
        {
 
1851
                const GstStructure *s;
 
1852
                gint progress;
 
1853
 
 
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");
 
1857
                        break;
 
1858
                }
 
1859
                if (stream == NULL) {
 
1860
                        rb_debug ("got buffering message for unknown stream (%d)", progress);
 
1861
                        break;
 
1862
                }
 
1863
 
 
1864
                if (progress >= 100) {
 
1865
                        GError *error = NULL;
 
1866
                        switch (stream->state) {
 
1867
                        case PREROLLING:
 
1868
                                rb_debug ("stream %s is buffered, now waiting", stream->uri);
 
1869
                                stream->state = WAITING;
 
1870
                                break;
 
1871
 
 
1872
                        case WAITING_EOS:
 
1873
                                /* hmm, not sure */
 
1874
                                break;
 
1875
 
 
1876
                        case PREROLL_PLAY:
 
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);
 
1880
                                }
 
1881
                                break;
 
1882
 
 
1883
                        default:
 
1884
                                rb_debug ("stream %s is buffered, resuming", stream->uri);
 
1885
                                link_and_unblock_stream (stream, &error);
 
1886
                                if (error) {
 
1887
                                        g_warning ("couldn't restart newly buffered stream: %s", error->message);
 
1888
                                        g_clear_error (&error);
 
1889
                                }
 
1890
                                break;
 
1891
                        }
 
1892
                } else {
 
1893
                        switch (stream->state) {
 
1894
                        case PREROLLING:
 
1895
                        case WAITING:
 
1896
                                rb_debug ("still buffering, %d", progress);
 
1897
                                stream->state = PREROLLING;
 
1898
                                break;
 
1899
 
 
1900
                        case WAITING_EOS:
 
1901
                                /* not sure */
 
1902
                                break;
 
1903
 
 
1904
                        case FADING_OUT:
 
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? */
 
1909
 
 
1910
                                /* since we're abandoning this stream, pretend it's not buffering */
 
1911
                                progress = 100;
 
1912
                                break;
 
1913
                        default:
 
1914
                                rb_debug ("stream buffering, stopping playback");
 
1915
                                unlink_and_block_stream (stream);
 
1916
                                break;
 
1917
                        }
 
1918
                }
 
1919
 
 
1920
                _rb_player_emit_buffering (RB_PLAYER (player), stream->stream_data, progress);
 
1921
                break;
 
1922
        }
 
1923
        case GST_MESSAGE_ELEMENT:
 
1924
        {
 
1925
                const GstStructure *s;
 
1926
                const char *name;
 
1927
 
 
1928
                if (gst_is_missing_plugin_message (message)) {
 
1929
                        rb_player_gst_xfade_handle_missing_plugin_message (player, stream, message);
 
1930
                        break;
 
1931
                }
 
1932
 
 
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)) {
 
1937
                        char *details;
 
1938
                        const char *uri = "unknown-stream";
 
1939
 
 
1940
                        if (stream != NULL) {
 
1941
                                uri = stream->uri;
 
1942
                        }
 
1943
 
 
1944
                        details = gst_structure_to_string (s);
 
1945
                        rb_debug_realf ("check-imperfect", __FILE__, __LINE__, TRUE, "%s: %s", uri, details);
 
1946
                        g_free (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);
 
1951
                        } else {
 
1952
                                rb_debug ("got redirect to %s, but no active stream found", uri);
 
1953
                        }
 
1954
                }
 
1955
                break;
 
1956
        }
 
1957
        default:
 
1958
                break;
 
1959
        }
 
1960
 
 
1961
        if (stream != NULL)
 
1962
                g_object_unref (stream);
 
1963
 
 
1964
        /* emit message signals too, so plugins can process bus messages */
 
1965
        gst_bus_async_signal_func (bus, message, NULL);
 
1966
 
 
1967
        return TRUE;
 
1968
}
 
1969
 
 
1970
static void
 
1971
stream_source_setup_cb (GstElement *decoder, GstElement *source, RBXFadeStream *stream)
 
1972
{
 
1973
        rb_debug ("got source notification for stream %s", stream->uri);
 
1974
        g_signal_emit (stream->player, signals[PREPARE_SOURCE], 0, stream->uri, source);
 
1975
}
 
1976
 
 
1977
/* links uridecodebin src pads to the rest of the output pipeline */
 
1978
static void
 
1979
stream_pad_added_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
 
1980
{
 
1981
        GstCaps *caps;
 
1982
        GstStructure *structure;
 
1983
        const char *mediatype;
 
1984
        GstPad *vpad;
 
1985
 
 
1986
        /* make sure this is an audio pad */
 
1987
        caps = gst_pad_query_caps (pad, NULL);
 
1988
        if (caps == NULL) {
 
1989
                caps = gst_pad_query_caps (pad, NULL);
 
1990
        }
 
1991
 
 
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);
 
1995
                return;
 
1996
        }
 
1997
 
 
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");
 
2005
        } else {
 
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;
 
2011
 
 
2012
                stream->decoder_pad = gst_object_ref (pad);
 
2013
        }
 
2014
        
 
2015
        gst_caps_unref (caps);
 
2016
}
 
2017
 
 
2018
static void
 
2019
stream_pad_removed_cb (GstElement *decoder, GstPad *pad, RBXFadeStream *stream)
 
2020
{
 
2021
        if (pad == stream->decoder_pad) {
 
2022
                rb_debug ("active output pad for stream %s removed", stream->uri);
 
2023
                stream->decoder_linked = FALSE;
 
2024
 
 
2025
                gst_object_unref (stream->decoder_pad);
 
2026
                stream->decoder_pad = NULL;
 
2027
        }
 
2028
}
 
2029
 
 
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
 
2032
 * it here.
 
2033
 *
 
2034
 * when an EOS event is received, a bus message is posted, and any streams
 
2035
 * in the WAITING_EOS state are started.
 
2036
 *
 
2037
 * when a new segment event is received, the stream base time is updated
 
2038
 * (mostly for seeking)
 
2039
 *
 
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.
 
2042
 */
 
2043
static GstPadProbeReturn
 
2044
stream_src_event_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
2045
{
 
2046
        GstMessage *msg;
 
2047
        GstEvent *event;
 
2048
        GstStructure *s;
 
2049
 
 
2050
        event = GST_EVENT (info->data);
 
2051
 
 
2052
        switch (GST_EVENT_TYPE (event)) {
 
2053
        case GST_EVENT_EOS:
 
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);
 
2058
 
 
2059
                /* start playing any streams that were waiting on an EOS
 
2060
                 * (are we really allowed to do this on a stream thread?)
 
2061
                 */
 
2062
                start_waiting_eos_streams (stream->player);
 
2063
                break;
 
2064
 
 
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);
 
2070
                break;
 
2071
 
 
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;
 
2076
 
 
2077
        default:
 
2078
                rb_debug ("got %s event for stream %s", GST_EVENT_TYPE_NAME (event), stream->uri);
 
2079
                break;
 
2080
        }
 
2081
 
 
2082
        return GST_PAD_PROBE_OK;
 
2083
}
 
2084
 
 
2085
/*
 
2086
 * stream playback bin:
 
2087
 *
 
2088
 * src [ ! queue ] ! decodebin ! audioconvert ! audioresample ! caps ! queue ! volume
 
2089
 *
 
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.
 
2094
 *
 
2095
 * the volume element is used for crossfading.
 
2096
 */
 
2097
static RBXFadeStream *
 
2098
create_stream (RBPlayerGstXFade *player, const char *uri, gpointer stream_data, GDestroyNotify stream_data_destroy)
 
2099
{
 
2100
        RBXFadeStream *stream;
 
2101
        GstCaps *caps;
 
2102
        GArray *stream_filters = NULL;
 
2103
        GstElement *tail;
 
2104
        gint i;
 
2105
 
 
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;
 
2113
 
 
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;
 
2118
                        break;
 
2119
                }
 
2120
        }
 
2121
 
 
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);
 
2129
                return NULL;
 
2130
        }
 
2131
        gst_object_ref (stream->decoder);
 
2132
        g_object_set (stream->decoder, "uri", uri, NULL);
 
2133
 
 
2134
        /* connect uridecodebin to audioconvert when it creates its output pad */
 
2135
        g_signal_connect_object (stream->decoder,
 
2136
                                 "source-setup",
 
2137
                                 G_CALLBACK (stream_source_setup_cb),
 
2138
                                 stream,
 
2139
                                 0);
 
2140
        g_signal_connect_object (stream->decoder,
 
2141
                                 "pad-added",
 
2142
                                 G_CALLBACK (stream_pad_added_cb),
 
2143
                                 stream,
 
2144
                                 0);
 
2145
        g_signal_connect_object (stream->decoder,
 
2146
                                 "pad-removed",
 
2147
                                 G_CALLBACK (stream_pad_removed_cb),
 
2148
                                 stream,
 
2149
                                 0);
 
2150
 
 
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);
 
2155
                return NULL;
 
2156
        }
 
2157
 
 
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);
 
2162
                return NULL;
 
2163
        }
 
2164
        gst_object_ref (stream->audioconvert);
 
2165
 
 
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);
 
2170
                return NULL;
 
2171
        }
 
2172
        gst_object_ref (stream->audioresample);
 
2173
 
 
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);
 
2178
                return NULL;
 
2179
        }
 
2180
        gst_object_ref (stream->capsfilter);
 
2181
 
 
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,
 
2187
                                    NULL);
 
2188
        g_object_set (stream->capsfilter, "caps", caps, NULL);
 
2189
        gst_caps_unref (caps);
 
2190
 
 
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);
 
2195
                return NULL;
 
2196
        }
 
2197
        gst_object_ref (stream->volume);
 
2198
 
 
2199
        g_signal_connect_object (stream->volume,
 
2200
                                 "notify::volume",
 
2201
                                 G_CALLBACK (volume_changed_cb),
 
2202
                                 player, 0);
 
2203
 
 
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);
 
2207
 
 
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)));
 
2210
 
 
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);
 
2215
                return NULL;
 
2216
        }
 
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.
 
2221
         */
 
2222
        g_object_set (stream->preroll,
 
2223
                      "min-threshold-time", GST_SECOND,
 
2224
                      "max-size-buffers", 1000,
 
2225
                      NULL);
 
2226
 
 
2227
        gst_bin_add_many (GST_BIN (stream),
 
2228
                          stream->decoder,
 
2229
                          stream->identity,
 
2230
                          stream->audioconvert,
 
2231
                          stream->audioresample,
 
2232
                          stream->capsfilter,
 
2233
                          stream->preroll,
 
2234
                          stream->volume,
 
2235
                          NULL);
 
2236
        gst_element_link_many (stream->audioconvert,
 
2237
                               stream->audioresample,
 
2238
                               stream->capsfilter,
 
2239
                               stream->preroll,
 
2240
                               stream->volume,
 
2241
                               NULL);
 
2242
 
 
2243
        if (rb_debug_matches ("check-imperfect", __FILE__)) {
 
2244
 
 
2245
                if (rb_debug_matches ("check-imperfect-timestamp", __FILE__)) {
 
2246
                        g_object_set (stream->identity, "check-imperfect-timestamp", TRUE, NULL);
 
2247
                }
 
2248
                if (rb_debug_matches ("check-imperfect-offset", __FILE__)) {
 
2249
                        g_object_set (stream->identity, "check-imperfect-offset", TRUE, NULL);
 
2250
                }
 
2251
        }
 
2252
        stream->src_pad = gst_element_get_static_pad (stream->volume, "src");
 
2253
 
 
2254
        /* link in any per-stream filters after the identity element, with an
 
2255
         * audioconvert before each.
 
2256
         */
 
2257
        tail = stream->identity;
 
2258
        g_signal_emit (player, signals[GET_STREAM_FILTERS], 0, uri, &stream_filters);
 
2259
        if (stream_filters != NULL) {
 
2260
                int i;
 
2261
                for (i = 0; i < stream_filters->len; i++) {
 
2262
                        GValue *v = &g_array_index (stream_filters, GValue, i);
 
2263
                        GstElement *filter;
 
2264
                        GstElement *audioconvert;
 
2265
 
 
2266
                        audioconvert = gst_element_factory_make ("audioconvert", NULL);
 
2267
                        filter = GST_ELEMENT (g_value_get_object (v));
 
2268
 
 
2269
                        gst_bin_add_many (GST_BIN (stream), audioconvert, filter, NULL);
 
2270
                        gst_element_link_many (tail, audioconvert, filter, NULL);
 
2271
                        tail = filter;
 
2272
                }
 
2273
 
 
2274
                g_array_unref (stream_filters);
 
2275
        }
 
2276
        gst_element_link (tail, stream->audioconvert);
 
2277
 
 
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);
 
2281
 
 
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,
 
2286
                           stream,
 
2287
                           NULL);
 
2288
 
 
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));
 
2291
 
 
2292
        return stream;
 
2293
}
 
2294
 
 
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
 
2307
 */
 
2308
static gboolean
 
2309
actually_start_stream (RBXFadeStream *stream, GError **error)
 
2310
{
 
2311
        RBPlayerGstXFade *player = stream->player;
 
2312
        gboolean ret = TRUE;
 
2313
        gboolean need_reap = FALSE;
 
2314
        gboolean playing;
 
2315
        GList *l;
 
2316
        GList *to_fade;
 
2317
 
 
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:
 
2321
 
 
2322
                to_fade = NULL;
 
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;
 
2326
 
 
2327
                        if (pstream == stream)
 
2328
                                continue;
 
2329
 
 
2330
                        switch (pstream->state) {
 
2331
                        case FADING_IN:
 
2332
                        case PLAYING:
 
2333
                                rb_debug ("stream %s is playing; crossfading -> FADING_OUT", pstream->uri);
 
2334
                                to_fade = g_list_prepend (to_fade, g_object_ref (pstream));
 
2335
                                break;
 
2336
 
 
2337
                        case PAUSED:
 
2338
                        case WAITING_EOS:
 
2339
                        case SEEKING:
 
2340
                        case SEEKING_PAUSED:
 
2341
                        case PREROLLING:
 
2342
                        case PREROLL_PLAY:
 
2343
                                rb_debug ("stream %s is paused; replacing it", pstream->uri);
 
2344
                                pstream->state = PENDING_REMOVE;
 
2345
                                /* fall through */
 
2346
                        case PENDING_REMOVE:
 
2347
                                need_reap = TRUE;
 
2348
                                break;
 
2349
 
 
2350
                        default:
 
2351
                                break;
 
2352
                        }
 
2353
                }
 
2354
 
 
2355
                g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
2356
 
 
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;
 
2361
 
 
2362
                        switch (pstream->state) {
 
2363
                        case FADING_IN:
 
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);
 
2367
                                /* fall through */
 
2368
 
 
2369
                        case PLAYING:
 
2370
                                start_stream_fade (pstream, fade_out_start, 0.0f, fade_out_time);
 
2371
                                pstream->state = FADING_OUT;
 
2372
 
 
2373
                                start_stream_fade (stream, 0.0f, 1.0f, stream->crossfade);
 
2374
                                break;
 
2375
 
 
2376
                        default:
 
2377
                                /* shouldn't happen, but ignore it if it does */
 
2378
                                break;
 
2379
                        }
 
2380
 
 
2381
                        g_object_unref (pstream);
 
2382
                }
 
2383
                g_list_free (to_fade);
 
2384
 
 
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);
 
2389
                }
 
2390
 
 
2391
                ret = link_and_unblock_stream (stream, error);
 
2392
                break;
 
2393
 
 
2394
        case RB_PLAYER_PLAY_AFTER_EOS:
 
2395
 
 
2396
                g_rec_mutex_lock (&player->priv->stream_list_lock);
 
2397
 
 
2398
                playing = FALSE;
 
2399
                for (l = player->priv->streams; l != NULL; l = l->next) {
 
2400
                        RBXFadeStream *pstream = (RBXFadeStream *)l->data;
 
2401
                        if (pstream == stream)
 
2402
                                continue;
 
2403
 
 
2404
                        switch (pstream->state) {
 
2405
                        case PLAYING:
 
2406
                        case FADING_IN:
 
2407
                        case FADING_OUT:
 
2408
                                rb_debug ("stream %s is already playing", pstream->uri);
 
2409
                                playing = TRUE;
 
2410
                                break;
 
2411
                        case PAUSED:
 
2412
                                rb_debug ("stream %s is paused; replacing it", pstream->uri);
 
2413
                                pstream->state = PENDING_REMOVE;
 
2414
                        case PENDING_REMOVE:
 
2415
                                need_reap = TRUE;
 
2416
                                break;
 
2417
                        default:
 
2418
                                break;
 
2419
                        }
 
2420
                }
 
2421
 
 
2422
                g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
2423
        
 
2424
                if (playing) {
 
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;
 
2429
                } else {
 
2430
                        rb_debug ("no playing stream found, so starting immediately");
 
2431
                        ret = link_and_unblock_stream (stream, error);
 
2432
                }
 
2433
                break;
 
2434
 
 
2435
        case RB_PLAYER_PLAY_REPLACE:
 
2436
                /* replace any existing playing stream */
 
2437
                g_rec_mutex_lock (&player->priv->stream_list_lock);
 
2438
 
 
2439
                for (l = player->priv->streams; l != NULL; l = l->next) {
 
2440
                        RBXFadeStream *pstream = (RBXFadeStream *)l->data;
 
2441
                        if (pstream == stream)
 
2442
                                continue;
 
2443
 
 
2444
                        switch (pstream->state) {
 
2445
                        case PLAYING:
 
2446
                        case PAUSED:
 
2447
                        case FADING_IN:
 
2448
                        case PENDING_REMOVE:
 
2449
                                /* kill this one */
 
2450
                                rb_debug ("stopping stream %s (replaced by new stream)", pstream->uri);
 
2451
                                need_reap = TRUE;
 
2452
                                pstream->state = PENDING_REMOVE;
 
2453
                                break;
 
2454
 
 
2455
                        default:
 
2456
                                /* let it go */
 
2457
                                break;
 
2458
                        }
 
2459
                }
 
2460
 
 
2461
                g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
2462
 
 
2463
                ret = link_and_unblock_stream (stream, error);
 
2464
                break;
 
2465
 
 
2466
        default:
 
2467
                g_assert_not_reached ();
 
2468
        }
 
2469
 
 
2470
        if (need_reap) {
 
2471
                schedule_stream_reap (player);
 
2472
        }
 
2473
 
 
2474
        return ret;
 
2475
}
 
2476
 
 
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
 
2480
 * to happen.
 
2481
 */
 
2482
static GstPadProbeReturn
 
2483
stream_src_blocked_cb (GstPad *pad, GstPadProbeInfo *info, RBXFadeStream *stream)
 
2484
{
 
2485
        GError *error = NULL;
 
2486
        gboolean start_stream = FALSE;
 
2487
 
 
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;
 
2493
        }
 
2494
        stream->src_blocked = TRUE;
 
2495
 
 
2496
        g_object_set (stream->preroll,
 
2497
                      "min-threshold-time", G_GINT64_CONSTANT (0),
 
2498
                      "max-size-buffers", 200,          /* back to normal value */
 
2499
                      NULL);
 
2500
 
 
2501
        if (stream->use_buffering) {
 
2502
                rb_debug ("stream %s requires buffering", stream->uri);
 
2503
                switch (stream->state) {
 
2504
                case PREROLL_PLAY:
 
2505
                        post_stream_playing_message (stream, TRUE);
 
2506
                        break;
 
2507
                default:
 
2508
                        break;
 
2509
                }
 
2510
                g_mutex_unlock (&stream->lock);
 
2511
                return GST_PAD_PROBE_OK;
 
2512
        }
 
2513
 
 
2514
        /* update stream state */
 
2515
        switch (stream->state) {
 
2516
        case PREROLLING:
 
2517
                rb_debug ("stream %s is prerolled, not starting yet -> WAITING", stream->uri);
 
2518
                stream->state = WAITING;
 
2519
                break;
 
2520
        case PREROLL_PLAY:
 
2521
                rb_debug ("stream %s is prerolled, need to start it", stream->uri);
 
2522
                start_stream = TRUE;
 
2523
                break;
 
2524
        default:
 
2525
                rb_debug ("didn't expect to get preroll completion callback in this state (%d)", stream->state);
 
2526
                break;
 
2527
        }
 
2528
        
 
2529
        g_mutex_unlock (&stream->lock);
 
2530
        
 
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);
 
2535
                }
 
2536
        }
 
2537
 
 
2538
        return GST_PAD_PROBE_OK;
 
2539
}
 
2540
 
 
2541
/*
 
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.
 
2547
 *
 
2548
 * must be called *without* the stream list lock?
 
2549
 */
 
2550
static void
 
2551
preroll_stream (RBPlayerGstXFade *player, RBXFadeStream *stream)
 
2552
{
 
2553
        GstStateChangeReturn state;
 
2554
        GstMessage *message;
 
2555
        GstBus *bus;
 
2556
 
 
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,
 
2561
                                   stream,
 
2562
                                   NULL);
 
2563
 
 
2564
        stream->emitted_playing = FALSE;
 
2565
        stream->state = PREROLLING;
 
2566
        state = gst_element_set_state (GST_ELEMENT (stream), GST_STATE_PAUSED);
 
2567
        switch (state) {
 
2568
        case GST_STATE_CHANGE_FAILURE:
 
2569
                rb_debug ("preroll for stream %s failed (state change failed)", stream->uri);
 
2570
 
 
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);
 
2578
                }
 
2579
                g_object_unref (bus);
 
2580
                break;
 
2581
 
 
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);
 
2585
                break;
 
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.
 
2591
                 */
 
2592
                break;
 
2593
        default:
 
2594
                g_assert_not_reached();
 
2595
        }
 
2596
}
 
2597
 
 
2598
/*
 
2599
 * returns the RBXFadeStream, playback position, and duration of the current
 
2600
 * playing stream.
 
2601
 */
 
2602
static gboolean
 
2603
get_times_and_stream (RBPlayerGstXFade *player, RBXFadeStream **pstream, gint64 *pos, gint64 *duration)
 
2604
{
 
2605
        gboolean got_time = FALSE;
 
2606
        gboolean buffering = FALSE;
 
2607
        RBXFadeStream *stream;
 
2608
 
 
2609
        if (player->priv->pipeline == NULL)
 
2610
                return FALSE;
 
2611
 
 
2612
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
2613
        
 
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);
 
2619
                        stream = NULL;
 
2620
                } else {
 
2621
                        rb_debug ("found buffering stream %s as current", stream->uri);
 
2622
                        buffering = TRUE;
 
2623
                }
 
2624
        }
 
2625
 
 
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);
 
2629
        }
 
2630
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
2631
 
 
2632
        if (stream != NULL) {
 
2633
                if (pstream != NULL) {
 
2634
                        *pstream = stream;
 
2635
                }
 
2636
 
 
2637
                if (pos != NULL) {
 
2638
                        if (buffering) {
 
2639
                                *pos = 0;
 
2640
                        } else if (stream->state == PAUSED) {
 
2641
                                *pos = -1;
 
2642
 
 
2643
                                gst_element_query_position (stream->volume, GST_FORMAT_TIME, pos);
 
2644
                        } else {
 
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.
 
2648
                                 */
 
2649
                                *pos = -1;
 
2650
                                gst_element_query_position (player->priv->pipeline, GST_FORMAT_TIME, pos);
 
2651
                                if (*pos != -1) {
 
2652
                                        *pos -= stream->base_time;
 
2653
                                } else {
 
2654
                                        rb_debug ("position query failed");
 
2655
                                }
 
2656
                        }
 
2657
                }
 
2658
 
 
2659
                if (duration != NULL) {
 
2660
                        *duration = -1;
 
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
 
2663
                         * linked element.
 
2664
                         */
 
2665
                        gst_element_query_duration (stream->volume, GST_FORMAT_TIME, duration);
 
2666
                }
 
2667
                got_time = TRUE;
 
2668
                if (pstream == NULL) {
 
2669
                        g_object_unref (stream);
 
2670
                }
 
2671
        } else {
 
2672
                rb_debug ("not playing");
 
2673
        }
 
2674
 
 
2675
        return got_time;
 
2676
}
 
2677
 
 
2678
static gboolean
 
2679
tick_timeout (RBPlayerGstXFade *player)
 
2680
{
 
2681
        gint64 pos = -1;
 
2682
        gint64 duration = -1;
 
2683
        RBXFadeStream *stream = NULL;
 
2684
 
 
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);
 
2688
        }
 
2689
 
 
2690
        return TRUE;
 
2691
}
 
2692
 
 
2693
static gboolean
 
2694
emit_volume_changed_idle (RBPlayerGstXFade *player)
 
2695
{
 
2696
        double vol;
 
2697
 
 
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);
 
2701
        } else {
 
2702
                vol = player->priv->cur_volume;
 
2703
        }
 
2704
 
 
2705
        _rb_player_emit_volume_changed (RB_PLAYER (player), vol);
 
2706
        return FALSE;
 
2707
}
 
2708
 
 
2709
static void
 
2710
stream_volume_changed (GObject *element, GParamSpec *pspec, RBPlayerGstXFade *player)
 
2711
{
 
2712
        double v;
 
2713
 
 
2714
        g_object_get (element, "volume", &v, NULL);
 
2715
        player->priv->cur_volume = v;
 
2716
 
 
2717
        g_idle_add ((GSourceFunc) emit_volume_changed_idle, player);
 
2718
}
 
2719
 
 
2720
/*
 
2721
 * output sink + adder pipeline:
 
2722
 *
 
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
 
2726
 *
 
2727
 * pipeline = silencebin ! adder ! outputbin
 
2728
 *
 
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.
 
2732
 *
 
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
 
2736
 */
 
2737
 
 
2738
static void
 
2739
add_bus_watch (RBPlayerGstXFade *player)
 
2740
{
 
2741
        GstBus *bus;
 
2742
 
 
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);
 
2746
}
 
2747
 
 
2748
static gboolean
 
2749
start_sink_locked (RBPlayerGstXFade *player, GList **messages, GError **error)
 
2750
{
 
2751
        GstStateChangeReturn sr;
 
2752
        gboolean waiting;
 
2753
        GError *generic_error = NULL;
 
2754
        GstBus *bus;
 
2755
 
 
2756
        g_set_error (&generic_error,
 
2757
                     RB_PLAYER_ERROR,
 
2758
                     RB_PLAYER_ERROR_INTERNAL,          /* ? */
 
2759
                     _("Failed to open output device"));
 
2760
 
 
2761
        rb_debug ("starting sink");
 
2762
 
 
2763
        /* first, start the output bin.
 
2764
         * this won't preroll until we start the silence bin.
 
2765
         */
 
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);
 
2770
                return FALSE;
 
2771
        }
 
2772
 
 
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);
 
2778
                return FALSE;
 
2779
        }
 
2780
 
 
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);
 
2786
                return FALSE;
 
2787
        }
 
2788
 
 
2789
        /* now wait for everything to finish */
 
2790
        waiting = TRUE;
 
2791
        bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
 
2792
        while (waiting) {
 
2793
                GstMessage *message;
 
2794
                GstState oldstate;
 
2795
                GstState newstate;
 
2796
                GstState pending;
 
2797
 
 
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);
 
2803
                        return FALSE;
 
2804
                }
 
2805
 
 
2806
                switch (GST_MESSAGE_TYPE (message)) {
 
2807
                case GST_MESSAGE_ERROR:
 
2808
                        {
 
2809
                                char *debug;
 
2810
                                GError *gst_error = NULL;
 
2811
                                RBXFadeStream *stream;
 
2812
 
 
2813
                                /* we only want to process errors from the sink here.
 
2814
                                 * errors from streams should go to the normal message handler.
 
2815
                                 */
 
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);
 
2821
                                } else {
 
2822
                                        gst_message_parse_error (message, &gst_error, &debug);
 
2823
                                        rb_debug ("got error message: %s (%s)", gst_error->message, debug);
 
2824
                                        gst_message_unref (message);
 
2825
                                        g_free (debug);
 
2826
 
 
2827
                                        if (error != NULL && *error == NULL) {
 
2828
                                                /* Translators: the parameter here is an error message */
 
2829
                                                g_set_error (error,
 
2830
                                                             RB_PLAYER_ERROR,
 
2831
                                                             RB_PLAYER_ERROR_INTERNAL,          /* ? */
 
2832
                                                             _("Failed to open output device: %s"),
 
2833
                                                             gst_error->message);
 
2834
                                        }
 
2835
                                        g_error_free (gst_error);
 
2836
                                        g_error_free (generic_error);
 
2837
 
 
2838
                                        gst_element_set_state (player->priv->outputbin, GST_STATE_NULL);
 
2839
                                        gst_element_set_state (player->priv->adder, GST_STATE_NULL);
 
2840
                                        gst_element_set_state (player->priv->silencebin, GST_STATE_NULL);
 
2841
                                        gst_object_unref (bus);
 
2842
                                        return FALSE;
 
2843
                                }
 
2844
                        }
 
2845
                        break;
 
2846
 
 
2847
                case GST_MESSAGE_STATE_CHANGED:
 
2848
                        {
 
2849
                                gst_message_parse_state_changed (message, &oldstate, &newstate, &pending);
 
2850
                                if (newstate == GST_STATE_PAUSED && pending == GST_STATE_VOID_PENDING) {
 
2851
                                        if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->outputbin)) {
 
2852
                                                rb_debug ("outputbin is now PAUSED");
 
2853
                                                waiting = FALSE;
 
2854
                                        } else if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->adder)) {
 
2855
                                                rb_debug ("adder is now PAUSED");
 
2856
                                        } else if (GST_MESSAGE_SRC (message) == GST_OBJECT (player->priv->silencebin)) {
 
2857
                                                rb_debug ("silencebin is now PAUSED");
 
2858
                                        }
 
2859
                                }
 
2860
                        }
 
2861
                        break;
 
2862
 
 
2863
                default:
 
2864
                        /* save the message to pass to the bus callback once we've dropped
 
2865
                         * the sink lock.
 
2866
                         */
 
2867
                        *messages = g_list_append (*messages, gst_message_ref (message));
 
2868
                        break;
 
2869
                }
 
2870
 
 
2871
                gst_message_unref (message);
 
2872
        }
 
2873
        gst_object_unref (bus);
 
2874
 
 
2875
        /* if the sink provides a 'volume' property, use that to control output volume */
 
2876
        player->priv->volume_handler = rb_player_gst_find_element_with_property (player->priv->sink, "volume");
 
2877
        if (player->priv->volume_handler == NULL) {
 
2878
                rb_debug ("sink doesn't provide volume control, using volume element");
 
2879
                player->priv->volume_handler = g_object_ref (player->priv->volume);
 
2880
        } else if (player->priv->volume_applied == 0) {
 
2881
                /* ignore the initial volume setting, allowing the
 
2882
                 * sink to restore its own volume.
 
2883
                 */
 
2884
                player->priv->volume_applied = 1;
 
2885
        }
 
2886
 
 
2887
        /* if there has been a volume change that we haven't applied, apply it now */
 
2888
        if (player->priv->volume_applied < player->priv->volume_changed) {
 
2889
                g_object_set (player->priv->volume_handler, "volume", player->priv->cur_volume, NULL);
 
2890
                player->priv->volume_applied = player->priv->volume_changed;
 
2891
        }
 
2892
 
 
2893
        g_signal_connect_object (player->priv->volume_handler,
 
2894
                                 "notify::volume",
 
2895
                                 G_CALLBACK (stream_volume_changed),
 
2896
                                 player, 0);
 
2897
 
 
2898
 
 
2899
        sr = gst_element_set_state (player->priv->silencebin, GST_STATE_PLAYING);
 
2900
        if (sr == GST_STATE_CHANGE_FAILURE) {
 
2901
                rb_debug ("silence bin state change failed");
 
2902
                g_propagate_error (error, generic_error);
 
2903
                return FALSE;
 
2904
        }
 
2905
 
 
2906
        sr = gst_element_set_state (player->priv->adder, GST_STATE_PLAYING);
 
2907
        if (sr == GST_STATE_CHANGE_FAILURE) {
 
2908
                rb_debug ("adder state change failed");
 
2909
                g_propagate_error (error, generic_error);
 
2910
                return FALSE;
 
2911
        }
 
2912
 
 
2913
        sr = gst_element_set_state (player->priv->outputbin, GST_STATE_PLAYING);
 
2914
        if (sr == GST_STATE_CHANGE_FAILURE) {
 
2915
                rb_debug ("output bin state change failed");
 
2916
                g_propagate_error (error, generic_error);
 
2917
                return FALSE;
 
2918
        }
 
2919
 
 
2920
        rb_debug ("sink playing");
 
2921
        player->priv->sink_state = SINK_PLAYING;
 
2922
 
 
2923
        /* set the pipeline to PLAYING so it selects a clock */
 
2924
        gst_element_set_state (player->priv->pipeline, GST_STATE_PLAYING);
 
2925
 
 
2926
        /* now that the sink is running, start polling for playing position.
 
2927
         * might want to replace this with a complicated set of pad probes
 
2928
         * to avoid polling, but duration queries on the sink are better
 
2929
         * as they account for internal buffering etc.  maybe there's a way
 
2930
         * to account for that in a pad probe callback on the sink's sink pad?
 
2931
         */
 
2932
        if (player->priv->tick_timeout_id == 0) {
 
2933
                gint ms_period = 1000 / RB_PLAYER_GST_XFADE_TICK_HZ;
 
2934
                player->priv->tick_timeout_id =
 
2935
                        g_timeout_add (ms_period,
 
2936
                                      (GSourceFunc) tick_timeout,
 
2937
                                      player);
 
2938
        }
 
2939
        return TRUE;
 
2940
}
 
2941
 
 
2942
static gboolean
 
2943
start_sink (RBPlayerGstXFade *player, GError **error)
 
2944
{
 
2945
        GList *messages = NULL;
 
2946
        GList *t;
 
2947
        GstBus *bus;
 
2948
        gboolean ret;
 
2949
 
 
2950
        g_rec_mutex_lock (&player->priv->sink_lock);
 
2951
        switch (player->priv->sink_state) {
 
2952
        case SINK_NULL:
 
2953
                g_assert_not_reached ();
 
2954
                break;
 
2955
 
 
2956
        case SINK_STOPPED:
 
2957
                /* prevent messages from being processed by the main thread while we're starting the sink */
 
2958
                g_source_remove (player->priv->bus_watch_id);
 
2959
                ret = start_sink_locked (player, &messages, error);
 
2960
                add_bus_watch (player);
 
2961
                break;
 
2962
 
 
2963
        case SINK_PLAYING:
 
2964
                ret = TRUE;
 
2965
                break;
 
2966
 
 
2967
        default:
 
2968
                g_assert_not_reached ();
 
2969
        }
 
2970
        g_rec_mutex_unlock (&player->priv->sink_lock);
 
2971
 
 
2972
        bus = gst_element_get_bus (GST_ELEMENT (player->priv->pipeline));
 
2973
        for (t = messages; t != NULL; t = t->next) {
 
2974
                rb_player_gst_xfade_bus_cb (bus, t->data, player);
 
2975
        }
 
2976
        gst_object_unref (bus);
 
2977
 
 
2978
        rb_list_destroy_free (messages, (GDestroyNotify) gst_mini_object_unref);
 
2979
        return ret;
 
2980
}
 
2981
 
 
2982
static gboolean
 
2983
stop_sink (RBPlayerGstXFade *player)
 
2984
{
 
2985
#if 0
 
2986
        GstStateChangeReturn sr;
 
2987
 
 
2988
        switch (player->priv->sink_state) {
 
2989
        case SINK_PLAYING:
 
2990
                rb_debug ("stopping sink");
 
2991
 
 
2992
                if (player->priv->tick_timeout_id != 0) {
 
2993
                        g_source_remove (player->priv->tick_timeout_id);
 
2994
                        player->priv->tick_timeout_id = 0;
 
2995
                }
 
2996
 
 
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");
 
3000
                        return FALSE;
 
3001
                }
 
3002
 
 
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");
 
3006
                        return FALSE;
 
3007
                }
 
3008
 
 
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");
 
3012
                        return FALSE;
 
3013
                }
 
3014
 
 
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");
 
3019
                }
 
3020
 
 
3021
                if (player->priv->volume_handler) {
 
3022
                        g_object_unref (player->priv->volume_handler);
 
3023
                        player->priv->volume_handler = NULL;
 
3024
                }
 
3025
 
 
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.
 
3029
                 */
 
3030
                gst_element_set_state (player->priv->pipeline, GST_STATE_READY);
 
3031
 
 
3032
                player->priv->sink_state = SINK_STOPPED;
 
3033
                break;
 
3034
 
 
3035
        case SINK_STOPPED:
 
3036
        case SINK_NULL:
 
3037
                break;
 
3038
        }
 
3039
 
 
3040
        return TRUE;
 
3041
#endif
 
3042
        return TRUE;
 
3043
}
 
3044
 
 
3045
 
 
3046
static gboolean
 
3047
create_sink (RBPlayerGstXFade *player, GError **error)
 
3048
{
 
3049
        const char *try_sinks[] = { "gsettingsaudiosink", "gconfaudiosink", "autoaudiosink" };
 
3050
        GstElement *audiotestsrc;
 
3051
        GstElement *audioconvert;
 
3052
        GstElement *audioresample;
 
3053
        GstElement *capsfilter;
 
3054
        GstElement *queue;
 
3055
        GstCaps *caps;
 
3056
        GstPad *filterpad;
 
3057
        GstPad *outputghostpad;
 
3058
        GstPad *ghostpad;
 
3059
        GstPad *reqpad;
 
3060
        GstPad *addersrcpad;
 
3061
        GstPadLinkReturn plr;
 
3062
        GList *l;
 
3063
        int i;
 
3064
 
 
3065
        if (player->priv->sink_state != SINK_NULL)
 
3066
                return TRUE;
 
3067
 
 
3068
        /* set filter caps.
 
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
 
3072
         * that rate.
 
3073
         */
 
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",
 
3079
                                    NULL);
 
3080
 
 
3081
        player->priv->pipeline = gst_pipeline_new ("rbplayer");
 
3082
        add_bus_watch (player);
 
3083
        g_object_notify (G_OBJECT (player), "bus");
 
3084
 
 
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 ||
 
3102
            queue == 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
 
3108
                 * available.
 
3109
                 */
 
3110
                g_set_error (error,
 
3111
                             RB_PLAYER_ERROR,
 
3112
                             RB_PLAYER_ERROR_GENERAL,
 
3113
                             _("Failed to create GStreamer element; check your installation"));
 
3114
                return FALSE;
 
3115
        }
 
3116
 
 
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) {
 
3120
                        break;
 
3121
                }
 
3122
        }
 
3123
        if (player->priv->sink == NULL) {
 
3124
                g_set_error (error,
 
3125
                             RB_PLAYER_ERROR,
 
3126
                             RB_PLAYER_ERROR_GENERAL,
 
3127
                             _("Failed to create audio output element; check your installation"));
 
3128
                return FALSE;
 
3129
        }
 
3130
 
 
3131
        g_object_set (player->priv->capsfilter, "caps", caps, NULL);
 
3132
        g_object_set (capsfilter, "caps", caps, NULL);
 
3133
 
 
3134
        g_object_set (queue, "max-size-buffers", 10, NULL);
 
3135
 
 
3136
        gst_bin_add_many (GST_BIN (player->priv->outputbin),
 
3137
                          player->priv->capsfilter,
 
3138
                          player->priv->volume,
 
3139
                          player->priv->filterbin,
 
3140
                          audioconvert,
 
3141
                          audioresample,
 
3142
                          capsfilter,
 
3143
                          player->priv->tee,
 
3144
                          queue,
 
3145
                          player->priv->sink,
 
3146
                          NULL);
 
3147
        if (gst_element_link_many (player->priv->capsfilter,
 
3148
                               player->priv->volume,
 
3149
                               player->priv->filterbin,
 
3150
                               audioconvert,
 
3151
                               audioresample,
 
3152
                               capsfilter,
 
3153
                               player->priv->tee,
 
3154
                               queue,
 
3155
                               player->priv->sink,
 
3156
                               NULL) == FALSE) {
 
3157
                g_warning ("minus one");
 
3158
                g_set_error (error,
 
3159
                             RB_PLAYER_ERROR,
 
3160
                             RB_PLAYER_ERROR_GENERAL,
 
3161
                             _("Failed to link GStreamer pipeline; check your installation"));
 
3162
                return FALSE;
 
3163
        }
 
3164
 
 
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);
 
3169
 
 
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);
 
3174
 
 
3175
        audioconvert = gst_element_factory_make ("audioconvert", "silenceconvert");
 
3176
 
 
3177
        capsfilter = gst_element_factory_make ("capsfilter", "silencecapsfilter");
 
3178
        g_object_set (capsfilter, "caps", caps, NULL);
 
3179
        gst_caps_unref (caps);
 
3180
 
 
3181
        if (audiotestsrc == NULL ||
 
3182
            audioconvert == NULL ||
 
3183
            capsfilter == NULL) {
 
3184
                g_set_error (error,
 
3185
                             RB_PLAYER_ERROR,
 
3186
                             RB_PLAYER_ERROR_GENERAL,
 
3187
                             _("Failed to create GStreamer element; check your installation"));
 
3188
                return FALSE;
 
3189
        }
 
3190
 
 
3191
        gst_bin_add_many (GST_BIN (player->priv->silencebin),
 
3192
                          audiotestsrc,
 
3193
                          audioconvert,
 
3194
                          capsfilter,
 
3195
                          NULL);
 
3196
        if (gst_element_link_many (audiotestsrc,
 
3197
                                   audioconvert,
 
3198
                                   capsfilter,
 
3199
                                   NULL) == FALSE) {
 
3200
                g_warning ("zero");
 
3201
                g_set_error (error,
 
3202
                             RB_PLAYER_ERROR,
 
3203
                             RB_PLAYER_ERROR_GENERAL,
 
3204
                             _("Failed to link GStreamer pipeline; check your installation"));
 
3205
                return FALSE;
 
3206
        }
 
3207
 
 
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);
 
3212
 
 
3213
        /* assemble stuff:
 
3214
         * - add everything to the pipeline
 
3215
         * - link adder to output bin
 
3216
         * - link silence bin to adder
 
3217
         */
 
3218
        gst_bin_add_many (GST_BIN (player->priv->pipeline),
 
3219
                          player->priv->adder,
 
3220
                          player->priv->outputbin,
 
3221
                          player->priv->silencebin,
 
3222
                          NULL);
 
3223
 
 
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) {
 
3227
                g_warning ("one");
 
3228
                g_set_error (error,
 
3229
                             RB_PLAYER_ERROR,
 
3230
                             RB_PLAYER_ERROR_GENERAL,
 
3231
                             _("Failed to link GStreamer pipeline; check your installation"));
 
3232
                return FALSE;
 
3233
        }
 
3234
 
 
3235
        reqpad = gst_element_get_request_pad (player->priv->adder, "sink_%u");
 
3236
        if (reqpad == NULL) {
 
3237
                g_warning ("two");
 
3238
                g_set_error (error,
 
3239
                             RB_PLAYER_ERROR,
 
3240
                             RB_PLAYER_ERROR_GENERAL,
 
3241
                             _("Failed to link GStreamer pipeline; check your installation"));
 
3242
                return FALSE;
 
3243
        }
 
3244
 
 
3245
        plr = gst_pad_link (ghostpad, reqpad);
 
3246
        if (plr != GST_PAD_LINK_OK) {
 
3247
                g_warning ("three");
 
3248
                g_set_error (error,
 
3249
                             RB_PLAYER_ERROR,
 
3250
                             RB_PLAYER_ERROR_GENERAL,
 
3251
                             _("Failed to link GStreamer pipeline; check your installation"));
 
3252
                return FALSE;
 
3253
        }
 
3254
 
 
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));
 
3258
        }
 
3259
        g_list_free (player->priv->waiting_tees);
 
3260
        player->priv->waiting_tees = NULL;
 
3261
 
 
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));
 
3264
        }
 
3265
        g_list_free (player->priv->waiting_filters);
 
3266
        player->priv->waiting_filters = NULL;
 
3267
 
 
3268
        player->priv->sink_state = SINK_STOPPED;
 
3269
        return TRUE;
 
3270
}
 
3271
 
 
3272
 
 
3273
 
 
3274
static gboolean
 
3275
rb_player_gst_xfade_open (RBPlayer *iplayer,
 
3276
                          const char *uri,
 
3277
                          gpointer stream_data,
 
3278
                          GDestroyNotify stream_data_destroy,
 
3279
                          GError **error)
 
3280
{
 
3281
        RBXFadeStream *stream;
 
3282
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3283
        gboolean reused = FALSE;
 
3284
        GList *t;
 
3285
 
 
3286
        /* create sink if we don't already have one */
 
3287
        if (create_sink (player, error) == FALSE)
 
3288
                return FALSE;
 
3289
 
 
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;
 
3294
 
 
3295
                switch (stream->state) {
 
3296
                case WAITING:
 
3297
                case PENDING_REMOVE:
 
3298
                case REUSING:
 
3299
                case SEEKING:
 
3300
                case SEEKING_PAUSED:
 
3301
                case SEEKING_EOS:
 
3302
                case PREROLLING:
 
3303
                case PREROLL_PLAY:
 
3304
                        break;
 
3305
 
 
3306
                case PLAYING:
 
3307
                case FADING_IN:
 
3308
                case FADING_OUT:
 
3309
                case FADING_OUT_PAUSED:
 
3310
                case WAITING_EOS:
 
3311
                case PAUSED:
 
3312
                        g_signal_emit (player,
 
3313
                                       signals[CAN_REUSE_STREAM], 0,
 
3314
                                       uri, stream->uri, GST_ELEMENT (stream),
 
3315
                                       &reused);
 
3316
                        break;
 
3317
                }
 
3318
 
 
3319
                if (reused) {
 
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;
 
3325
 
 
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..)
 
3328
                         */
 
3329
                        player->priv->streams = g_list_remove (player->priv->streams, stream);
 
3330
                        player->priv->streams = g_list_prepend (player->priv->streams, stream);
 
3331
                        break;
 
3332
                }
 
3333
        }
 
3334
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3335
        if (reused) {
 
3336
                return TRUE;
 
3337
        }
 
3338
 
 
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);
 
3343
                g_set_error (error,
 
3344
                             RB_PLAYER_ERROR,
 
3345
                             RB_PLAYER_ERROR_GENERAL,
 
3346
                             _("Failed to create GStreamer pipeline to play %s"),
 
3347
                             uri);
 
3348
                return FALSE;
 
3349
        }
 
3350
 
 
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);
 
3355
 
 
3356
        /* start prerolling it */
 
3357
        preroll_stream (player, stream);
 
3358
 
 
3359
        return TRUE;
 
3360
}
 
3361
 
 
3362
static gboolean
 
3363
stop_sink_later (RBPlayerGstXFade *player)
 
3364
{
 
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) {
 
3368
                stop_sink (player);
 
3369
        }
 
3370
        g_rec_mutex_unlock (&player->priv->sink_lock);
 
3371
 
 
3372
        return FALSE;
 
3373
}
 
3374
 
 
3375
static void
 
3376
maybe_stop_sink (RBPlayerGstXFade *player)
 
3377
{
 
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,
 
3383
                                       player);
 
3384
        }
 
3385
        g_rec_mutex_unlock (&player->priv->sink_lock);
 
3386
}
 
3387
 
 
3388
static gboolean
 
3389
rb_player_gst_xfade_close (RBPlayer *iplayer, const char *uri, GError **error)
 
3390
{
 
3391
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3392
        gboolean ret = TRUE;
 
3393
 
 
3394
        if (uri == NULL) {
 
3395
                GList *list;
 
3396
                GList *l;
 
3397
 
 
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);
 
3404
                }
 
3405
                g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3406
 
 
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);
 
3411
                }
 
3412
                g_list_free (list);
 
3413
        } else {
 
3414
                /* just stop and close the stream for the specified uri */
 
3415
                RBXFadeStream *stream;
 
3416
 
 
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);
 
3420
 
 
3421
                if (stream != NULL) {
 
3422
                        unlink_and_dispose_stream (player, stream);
 
3423
                        g_object_unref (stream);
 
3424
                } else {
 
3425
                        rb_debug ("can't find stream for %s", uri);
 
3426
                        /* XXX set error ?*/
 
3427
                        ret = FALSE;
 
3428
                }
 
3429
        }
 
3430
 
 
3431
        return ret;
 
3432
}
 
3433
 
 
3434
 
 
3435
static gboolean
 
3436
rb_player_gst_xfade_opened (RBPlayer *iplayer)
 
3437
{
 
3438
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3439
        RBXFadeStream *stream;
 
3440
        gboolean opened = FALSE;
 
3441
 
 
3442
        /* maybe replace this with just a flag somewhere? */
 
3443
 
 
3444
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
3445
 
 
3446
        stream = find_stream_by_state (player, PREROLLING | PREROLL_PLAY | WAITING_EOS | WAITING | FADING_IN | PLAYING | PAUSED);
 
3447
        if (stream != NULL) {
 
3448
                opened = TRUE;
 
3449
                g_object_unref (stream);
 
3450
        }
 
3451
 
 
3452
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3453
 
 
3454
        return opened;
 
3455
}
 
3456
 
 
3457
static gboolean
 
3458
rb_player_gst_xfade_play (RBPlayer *iplayer,
 
3459
                          RBPlayerPlayType play_type,
 
3460
                          gint64 crossfade,
 
3461
                          GError **error)
 
3462
{
 
3463
        RBXFadeStream *stream;
 
3464
        int stream_state;
 
3465
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3466
        gboolean ret = TRUE;
 
3467
 
 
3468
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
3469
 
 
3470
        /* is there anything to play? */
 
3471
        if (player->priv->streams == NULL) {
 
3472
                g_set_error (error,
 
3473
                             RB_PLAYER_ERROR,
 
3474
                             RB_PLAYER_ERROR_GENERAL,
 
3475
                             "Nothing to play");                /* should never happen */
 
3476
 
 
3477
                g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3478
                return FALSE;
 
3479
        }
 
3480
        
 
3481
        stream = g_list_first (player->priv->streams)->data;
 
3482
        g_object_ref (stream);
 
3483
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3484
 
 
3485
        /* make sure the sink is playing */
 
3486
        if (start_sink (player, error) == FALSE) {
 
3487
                g_object_unref (stream);
 
3488
                return FALSE;
 
3489
        }
 
3490
 
 
3491
        g_mutex_lock (&stream->lock);
 
3492
 
 
3493
        rb_debug ("playing stream %s, play type %d, crossfade %" G_GINT64_FORMAT, stream->uri, play_type, crossfade);
 
3494
 
 
3495
        /* handle transitional states while holding the lock, and handle states that
 
3496
         * require action outside it (lock precedence, mostly)
 
3497
         */
 
3498
        switch (stream->state) {
 
3499
        case PREROLLING:
 
3500
        case PREROLL_PLAY:
 
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;
 
3505
                break;
 
3506
        
 
3507
        case SEEKING_PAUSED:
 
3508
                rb_debug ("unpausing seeking stream %s", stream->uri);
 
3509
                stream->state = SEEKING;
 
3510
                break;
 
3511
 
 
3512
        case PENDING_REMOVE:
 
3513
                rb_debug ("hmm, can't play streams in PENDING_REMOVE state..");
 
3514
                break;
 
3515
 
 
3516
        default:
 
3517
                break;
 
3518
        }
 
3519
 
 
3520
        stream_state = stream->state;
 
3521
        g_mutex_unlock (&stream->lock);
 
3522
 
 
3523
        /* is the head stream already playing? */
 
3524
        switch (stream_state) {
 
3525
        case FADING_IN:
 
3526
        case FADING_OUT:
 
3527
        case FADING_OUT_PAUSED:
 
3528
        case PLAYING:
 
3529
        case SEEKING:
 
3530
        case SEEKING_EOS:
 
3531
                rb_debug ("stream %s is already playing", stream->uri);
 
3532
                _rb_player_emit_playing_stream (RB_PLAYER (player), stream->stream_data);
 
3533
                break;
 
3534
 
 
3535
        case PAUSED:
 
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);
 
3539
                break;
 
3540
 
 
3541
        case WAITING_EOS:
 
3542
        case WAITING:
 
3543
                stream->play_type = play_type;
 
3544
                stream->crossfade = crossfade;
 
3545
                ret = actually_start_stream (stream, error);
 
3546
                break;
 
3547
 
 
3548
        case REUSING:
 
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);
 
3557
                        } else {
 
3558
                                rb_debug ("unlinking stream %s for reuse", stream->uri);
 
3559
                                unlink_and_block_stream (stream);
 
3560
                        }
 
3561
                        break;
 
3562
                case RB_PLAYER_PLAY_AFTER_EOS:
 
3563
                        rb_debug ("waiting for EOS before reusing stream %s", stream->uri);
 
3564
                        break;
 
3565
                }
 
3566
                break;
 
3567
 
 
3568
        default:
 
3569
                break;
 
3570
        }
 
3571
 
 
3572
        g_object_unref (stream);
 
3573
 
 
3574
        return ret;
 
3575
}
 
3576
 
 
3577
static void
 
3578
rb_player_gst_xfade_pause (RBPlayer *iplayer)
 
3579
{
 
3580
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3581
        GList *l;
 
3582
        GList *to_fade = NULL;
 
3583
        gboolean done = FALSE;
 
3584
        double fade_out_start = 1.0f;
 
3585
        gint64 fade_out_time = PAUSE_FADE_LENGTH;
 
3586
 
 
3587
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
3588
 
 
3589
        for (l = player->priv->streams; l != NULL; l = l->next) {
 
3590
                RBXFadeStream *stream;
 
3591
                stream = (RBXFadeStream *)l->data;
 
3592
                switch (stream->state) {
 
3593
                case WAITING:
 
3594
                case WAITING_EOS:
 
3595
                        rb_debug ("stream %s is not yet playing, can't pause", stream->uri);
 
3596
                        break;
 
3597
 
 
3598
                case PREROLLING:
 
3599
                case PREROLL_PLAY:
 
3600
                        rb_debug ("stream %s is prerolling, can't pause", stream->uri);
 
3601
                        break;
 
3602
 
 
3603
                case REUSING:
 
3604
                        rb_debug ("stream %s is being reused, can't pause", stream->uri);
 
3605
                        break;
 
3606
 
 
3607
                case PAUSED:
 
3608
                case SEEKING_PAUSED:
 
3609
                case FADING_OUT_PAUSED:
 
3610
                        rb_debug ("stream %s is already paused", stream->uri);
 
3611
                        done = TRUE;
 
3612
                        break;
 
3613
 
 
3614
                case FADING_IN:
 
3615
                case PLAYING:
 
3616
                        rb_debug ("pausing stream %s -> FADING_OUT_PAUSED", stream->uri);
 
3617
                        to_fade = g_list_prepend (to_fade, g_object_ref (stream));
 
3618
                        done = TRUE;
 
3619
                        break;
 
3620
 
 
3621
                case SEEKING:
 
3622
                        rb_debug ("pausing seeking stream %s -> SEEKING_PAUSED", stream->uri);
 
3623
                        stream->state = SEEKING_PAUSED;
 
3624
                        done = TRUE;
 
3625
                        break;
 
3626
                case SEEKING_EOS:
 
3627
                        rb_debug ("stream %s is seeking after EOS -> SEEKING_PAUSED", stream->uri);
 
3628
                        stream->state = SEEKING_PAUSED;
 
3629
                        done = TRUE;
 
3630
                        break;
 
3631
 
 
3632
                case FADING_OUT:
 
3633
                        rb_debug ("stream %s is fading out, can't be bothered pausing it", stream->uri);
 
3634
                        break;
 
3635
 
 
3636
                case PENDING_REMOVE:
 
3637
                        rb_debug ("stream %s is done, can't pause", stream->uri);
 
3638
                        break;
 
3639
                }
 
3640
 
 
3641
                if (done)
 
3642
                        break;
 
3643
        }
 
3644
 
 
3645
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3646
 
 
3647
        for (l = to_fade; l != NULL; l = l->next) {
 
3648
                RBXFadeStream *stream = (RBXFadeStream *)l->data;
 
3649
 
 
3650
                switch (stream->state) {
 
3651
                case FADING_IN:
 
3652
                        g_object_get (stream->volume, "volume", &fade_out_start, NULL);
 
3653
                        fade_out_time = (gint64)(((double) PAUSE_FADE_LENGTH) * fade_out_start);
 
3654
 
 
3655
                case PLAYING:
 
3656
                        stream->state = FADING_OUT_PAUSED;
 
3657
                        start_stream_fade (stream, fade_out_start, 0.0f, fade_out_time);
 
3658
 
 
3659
                default:
 
3660
                        /* shouldn't happen, but ignore it if it does */
 
3661
                        break;
 
3662
                }
 
3663
 
 
3664
                g_object_unref (stream);
 
3665
        }
 
3666
        g_list_free (to_fade);
 
3667
        
 
3668
        if (done == FALSE)
 
3669
                rb_debug ("couldn't find a stream to pause");
 
3670
}
 
3671
 
 
3672
static gboolean
 
3673
rb_player_gst_xfade_playing (RBPlayer *iplayer)
 
3674
{
 
3675
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3676
        gboolean playing = FALSE;
 
3677
        RBXFadeStream *stream;
 
3678
 
 
3679
        if (player->priv->sink_state != SINK_PLAYING)
 
3680
                return FALSE;
 
3681
 
 
3682
        /* XXX maybe replace with just a flag? */
 
3683
 
 
3684
        g_rec_mutex_lock (&player->priv->stream_list_lock);
 
3685
 
 
3686
        stream = find_stream_by_state (player, PLAYING | FADING_IN);
 
3687
        if (stream != NULL) {
 
3688
                playing = TRUE;
 
3689
                g_object_unref (stream);
 
3690
        }
 
3691
        g_rec_mutex_unlock (&player->priv->stream_list_lock);
 
3692
        return playing;
 
3693
}
 
3694
 
 
3695
 
 
3696
static void
 
3697
rb_player_gst_xfade_set_volume (RBPlayer *iplayer, float volume)
 
3698
{
 
3699
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3700
 
 
3701
        player->priv->volume_changed++;
 
3702
        if (player->priv->volume_handler != NULL) {
 
3703
                gdouble v = (gdouble)volume;
 
3704
 
 
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);
 
3709
                } else {
 
3710
                        g_object_set (player->priv->volume_handler, "volume", v, NULL);
 
3711
                }
 
3712
                player->priv->volume_applied = player->priv->volume_changed;
 
3713
        }
 
3714
        player->priv->cur_volume = volume;
 
3715
}
 
3716
 
 
3717
 
 
3718
static float
 
3719
rb_player_gst_xfade_get_volume (RBPlayer *iplayer)
 
3720
{
 
3721
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3722
 
 
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);
 
3726
 
 
3727
        return player->priv->cur_volume;
 
3728
}
 
3729
 
 
3730
static gboolean
 
3731
rb_player_gst_xfade_seekable (RBPlayer *iplayer)
 
3732
{
 
3733
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3734
        gboolean can_seek = TRUE;
 
3735
        RBXFadeStream *stream;
 
3736
 
 
3737
        /* is this supposed to query the most recently opened stream,
 
3738
         * or the current playing stream?  I really don't know.
 
3739
         */
 
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);
 
3743
 
 
3744
        if (stream) {
 
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);
 
3749
                } else {
 
3750
                        gst_query_unref (query);
 
3751
 
 
3752
                        query = gst_query_new_duration (GST_FORMAT_TIME);
 
3753
                        can_seek = gst_element_query (stream->volume, query);
 
3754
                }
 
3755
                gst_query_unref (query);
 
3756
                g_object_unref (stream);
 
3757
        }
 
3758
 
 
3759
        return can_seek;
 
3760
}
 
3761
 
 
3762
static void
 
3763
rb_player_gst_xfade_set_time (RBPlayer *iplayer, gint64 time)
 
3764
{
 
3765
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3766
        RBXFadeStream *stream;
 
3767
 
 
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);
 
3771
 
 
3772
        if (stream == NULL) {
 
3773
                rb_debug ("got seek while no playing streams exist");
 
3774
                return;
 
3775
        }
 
3776
 
 
3777
        stream->seek_target = time;
 
3778
        switch (stream->state) {
 
3779
        case PAUSED:
 
3780
                rb_debug ("seeking in paused stream %s; target %" 
 
3781
                    G_GINT64_FORMAT, stream->uri, stream->seek_target);
 
3782
                perform_seek (stream);
 
3783
                break;
 
3784
 
 
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);
 
3791
                break;
 
3792
 
 
3793
        case FADING_IN:
 
3794
        case PLAYING:
 
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);
 
3799
                break;
 
3800
 
 
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.
 
3806
                 */
 
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,
 
3813
                                   stream,
 
3814
                                   NULL);
 
3815
                perform_seek (stream);
 
3816
                break;
 
3817
        default:
 
3818
                g_assert_not_reached ();
 
3819
        }
 
3820
 
 
3821
        g_object_unref (stream);
 
3822
}
 
3823
 
 
3824
static gint64
 
3825
rb_player_gst_xfade_get_time (RBPlayer *iplayer)
 
3826
{
 
3827
        gint64 pos = -1;
 
3828
        RBPlayerGstXFade *player = RB_PLAYER_GST_XFADE (iplayer);
 
3829
 
 
3830
        get_times_and_stream (player, NULL, &pos, NULL);
 
3831
        return pos;
 
3832
}
 
3833
 
 
3834
static gboolean
 
3835
need_pad_block (RBPlayerGstXFade *player)
 
3836
{
 
3837
        return (player->priv->sink_state == SINK_PLAYING);
 
3838
}
 
3839
 
 
3840
static gboolean
 
3841
rb_player_gst_xfade_add_tee (RBPlayerGstTee *iplayer, GstElement *element)
 
3842
{
 
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);
 
3846
                return TRUE;
 
3847
        }
 
3848
 
 
3849
        return rb_gst_add_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
 
3850
}
 
3851
 
 
3852
static gboolean
 
3853
rb_player_gst_xfade_remove_tee (RBPlayerGstTee *iplayer, GstElement *element)
 
3854
{
 
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);
 
3859
                return TRUE;
 
3860
        }
 
3861
 
 
3862
        return rb_gst_remove_tee (RB_PLAYER (player), player->priv->tee, element, need_pad_block (player));
 
3863
}
 
3864
 
 
3865
 
 
3866
static gboolean
 
3867
rb_player_gst_xfade_add_filter (RBPlayerGstFilter *iplayer, GstElement *element)
 
3868
{
 
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);
 
3872
                return TRUE;
 
3873
        }
 
3874
 
 
3875
        return rb_gst_add_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));
 
3876
}
 
3877
 
 
3878
 
 
3879
static gboolean
 
3880
rb_player_gst_xfade_remove_filter (RBPlayerGstFilter *iplayer, GstElement *element)
 
3881
{
 
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);
 
3886
                return TRUE;
 
3887
        }
 
3888
 
 
3889
        return rb_gst_remove_filter (RB_PLAYER (player), player->priv->filterbin, element, need_pad_block (player));
 
3890
}
 
3891