~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to player/rb-player-gst.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.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 -*- */
1
2
/*
2
3
 *  arch-tag: Implementation of GStreamer backends, with workarounds for bugs
3
4
 *
23
24
#include <config.h>
24
25
#include <gdk/gdk.h>
25
26
#include <gst/gst.h>
26
 
#include <gst/gstqueue.h>
27
27
#include <gst/gconf/gconf.h>
28
 
#include <gst/control/control.h>
29
 
#include <gst/control/dparam_smooth.h>
30
28
#include <math.h>
31
29
#include <string.h>
32
30
#include <stdlib.h>
39
37
#include "rb-debug.h"
40
38
#include "rb-marshal.h"
41
39
 
42
 
static void rb_player_class_init (RBPlayerClass *klass);
43
 
static void rb_player_init (RBPlayer *mp);
 
40
#ifdef WITH_DAAP_SUPPORT
 
41
#include "rb-daap-src.h"
 
42
#endif
 
43
 
 
44
G_DEFINE_TYPE(RBPlayer, rb_player, G_TYPE_OBJECT)
 
45
 
44
46
static void rb_player_finalize (GObject *object);
45
47
 
46
48
struct RBPlayerPrivate
47
49
{
48
50
        char *uri;
49
51
 
50
 
        GstElement *pipeline;
51
 
 
52
 
        GstElement *srcthread;
53
 
        GstElement *queue;
54
 
        GstElement *typefind;
55
 
        GstElement *waiting_bin;
56
 
        GstElement *src;
57
 
 
58
 
        GstElement *decoder;
59
 
        GstElement *volume;
60
 
        GstElement *audioconvert;
61
 
        GstElement *audioscale;
62
 
        GstElement *sink;
63
 
 
 
52
        GstElement *playbin;
 
53
 
 
54
        gboolean can_signal_direct_error;
64
55
        GError *error;
65
56
 
66
 
#ifdef HAVE_AUDIOCD
67
 
        MonkeyMediaAudioCD *cd;
68
 
#endif
69
 
 
70
 
        gboolean iradio_mode;
71
57
        gboolean playing;
72
58
 
 
59
        guint idle_error_id;
 
60
        guint idle_eos_id;
 
61
        guint idle_buffering_id;
 
62
        GHashTable *idle_info_ids;
 
63
 
73
64
        guint error_signal_id;
 
65
        guint buffering_signal_id;
74
66
 
75
 
        GstDParamManager *volume_dpmanager;
76
 
        GstDParam *volume_dparam;
77
67
        float cur_volume;
78
68
 
79
 
        GTimer *timer;
80
 
        long timer_add;
81
 
 
82
69
        guint tick_timeout_id;
83
70
};
84
71
 
86
73
{
87
74
        EOS,
88
75
        INFO,
89
 
        BUFFERING_BEGIN,
90
 
        BUFFERING_END,
91
 
        BUFFERING_PROGRESS,
92
76
        ERROR,
93
77
        TICK,
 
78
        BUFFERING,
94
79
        LAST_SIGNAL
95
80
} RBPlayerSignalType;
96
81
 
97
82
typedef struct
98
83
{
 
84
        int type;
99
85
        RBPlayer *object;
100
86
        RBMetaDataField info_field;
101
87
        GError *error;
102
88
        GValue *info;
 
89
        guint id;
103
90
} RBPlayerSignal;
104
91
 
105
92
static guint rb_player_signals[LAST_SIGNAL] = { 0 };
106
93
 
107
 
static GObjectClass *parent_class = NULL;
108
 
 
109
 
static gboolean rb_player_sync_pipeline (RBPlayer *mp, gboolean iradio_mode, GError **error);
110
 
static void rb_player_gst_free_pipeline (RBPlayer *player);
111
 
 
112
 
GType
113
 
rb_player_get_type (void)
114
 
{
115
 
        static GType type = 0;
116
 
 
117
 
        if (type == 0) {
118
 
                static const GTypeInfo our_info =
119
 
                {
120
 
                        sizeof (RBPlayerClass),
121
 
                        NULL,
122
 
                        NULL,
123
 
                        (GClassInitFunc) rb_player_class_init,
124
 
                        NULL,
125
 
                        NULL,
126
 
                        sizeof (RBPlayer),
127
 
                        0,
128
 
                        (GInstanceInitFunc) rb_player_init,
129
 
                };
130
 
 
131
 
                type = g_type_register_static (G_TYPE_OBJECT,
132
 
                                               "RBPlayer",
133
 
                                               &our_info, 0);
134
 
        }
135
 
 
136
 
        return type;
137
 
}
 
94
static gboolean rb_player_sync_pipeline (RBPlayer *mp);
 
95
static void rb_player_gst_free_playbin (RBPlayer *player);
138
96
 
139
97
static void
140
98
rb_player_class_init (RBPlayerClass *klass)
141
99
{
142
100
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
143
101
 
144
 
        parent_class = g_type_class_peek_parent (klass);
145
 
 
146
102
        object_class->finalize = rb_player_finalize;
147
103
 
148
104
        rb_player_signals[EOS] =
163
119
                              rb_marshal_VOID__INT_POINTER,
164
120
                              G_TYPE_NONE,
165
121
                              2, G_TYPE_INT, G_TYPE_POINTER);
166
 
        rb_player_signals[BUFFERING_BEGIN] =
167
 
                g_signal_new ("buffering_begin",
168
 
                              G_OBJECT_CLASS_TYPE (object_class),
169
 
                              G_SIGNAL_RUN_LAST,
170
 
                              G_STRUCT_OFFSET (RBPlayerClass, buffering_begin),
171
 
                              NULL, NULL,
172
 
                              g_cclosure_marshal_VOID__VOID,
173
 
                              G_TYPE_NONE,
174
 
                              0);
175
 
        rb_player_signals[BUFFERING_END] =
176
 
                g_signal_new ("buffering_end",
177
 
                              G_OBJECT_CLASS_TYPE (object_class),
178
 
                              G_SIGNAL_RUN_LAST,
179
 
                              G_STRUCT_OFFSET (RBPlayerClass, buffering_end),
180
 
                              NULL, NULL,
181
 
                              g_cclosure_marshal_VOID__VOID,
182
 
                              G_TYPE_NONE,
183
 
                              0);
184
 
        rb_player_signals[BUFFERING_PROGRESS] =
185
 
                g_signal_new ("buffering_progress",
186
 
                              G_OBJECT_CLASS_TYPE (object_class),
187
 
                              G_SIGNAL_RUN_LAST,
188
 
                              G_STRUCT_OFFSET (RBPlayerClass, buffering_progress),
189
 
                              NULL, NULL,
190
 
                              g_cclosure_marshal_VOID__INT,
191
 
                              G_TYPE_NONE,
192
 
                              1,
193
 
                              G_TYPE_INT);
194
122
        rb_player_signals[ERROR] =
195
123
                g_signal_new ("error",
196
124
                              G_OBJECT_CLASS_TYPE (object_class),
211
139
                              G_TYPE_NONE,
212
140
                              1,
213
141
                              G_TYPE_LONG);
 
142
        rb_player_signals[BUFFERING] =
 
143
                g_signal_new ("buffering",
 
144
                              G_OBJECT_CLASS_TYPE (object_class),
 
145
                              G_SIGNAL_RUN_LAST,
 
146
                              G_STRUCT_OFFSET (RBPlayerClass, buffering),
 
147
                              NULL, NULL,
 
148
                              g_cclosure_marshal_VOID__UINT,
 
149
                              G_TYPE_NONE,
 
150
                              1,
 
151
                              G_TYPE_UINT);
214
152
}
215
153
 
216
154
static gboolean
231
169
        gint ms_period = 1000 / RB_PLAYER_TICK_HZ;
232
170
 
233
171
        mp->priv = g_new0 (RBPlayerPrivate, 1);
234
 
 
235
 
#ifdef HAVE_AUDIOCD
236
 
        mp->priv->cd = monkey_media_audio_cd_new (NULL);
237
 
#endif  
238
 
 
239
172
        mp->priv->tick_timeout_id = g_timeout_add (ms_period, (GSourceFunc) tick_timeout, mp);
 
173
        mp->priv->idle_info_ids = g_hash_table_new (NULL, NULL);
 
174
        
240
175
}
241
176
 
242
177
static void
247
182
        mp = RB_PLAYER (object);
248
183
 
249
184
        g_source_remove (mp->priv->tick_timeout_id);
 
185
        g_hash_table_destroy (mp->priv->idle_info_ids);
250
186
 
251
 
        if (mp->priv->pipeline) {
252
 
                g_signal_handler_disconnect (G_OBJECT (mp->priv->pipeline),
 
187
        if (mp->priv->playbin) {
 
188
                g_signal_handler_disconnect (G_OBJECT (mp->priv->playbin),
253
189
                                             mp->priv->error_signal_id);
 
190
                g_signal_handler_disconnect (G_OBJECT (mp->priv->playbin),
 
191
                                             mp->priv->buffering_signal_id);
254
192
                
255
 
                gst_element_set_state (mp->priv->pipeline,
 
193
                gst_element_set_state (mp->priv->playbin,
256
194
                                       GST_STATE_NULL);
257
195
                
258
 
                rb_player_gst_free_pipeline (mp);
 
196
                rb_player_gst_free_playbin (mp);
259
197
        }
260
198
 
261
 
        if (mp->priv->timer)
262
 
                g_timer_destroy (mp->priv->timer);
263
 
        
264
 
        g_free (mp->priv->uri);
265
 
 
266
199
        g_free (mp->priv);
267
200
 
268
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
201
        G_OBJECT_CLASS (rb_player_parent_class)->finalize (object);
269
202
}
270
203
 
271
204
static void
272
 
rb_player_gst_free_pipeline (RBPlayer *player)
 
205
rb_player_gst_free_playbin (RBPlayer *player)
273
206
{
274
 
        if (player->priv->pipeline == NULL)
 
207
        if (player->priv->playbin == NULL)
275
208
                return;
276
209
        
277
 
        if (player->priv->volume_dpmanager) {
278
 
                gst_dpman_detach_dparam (player->priv->volume_dpmanager, "volume");
279
 
                gst_object_unref (GST_OBJECT (player->priv->volume_dparam));
280
 
                player->priv->volume_dpmanager = NULL;
281
 
        }
282
 
        gst_object_unref (GST_OBJECT (player->priv->pipeline));
283
 
        player->priv->pipeline = NULL;
284
 
}
285
 
 
286
 
static gboolean
287
 
eos_signal_idle (RBPlayer *mp)
288
 
{
289
 
        g_signal_emit (G_OBJECT (mp), rb_player_signals[EOS], 0);
290
 
 
291
 
        g_object_unref (G_OBJECT (mp));
292
 
 
293
 
        return FALSE;
294
 
}
295
 
 
296
 
static gboolean
297
 
buffering_begin_signal_idle (RBPlayer *mp)
298
 
{
299
 
        GDK_THREADS_ENTER ();
300
 
 
301
 
        g_signal_emit (G_OBJECT (mp), rb_player_signals[BUFFERING_BEGIN], 0);
302
 
        g_object_unref (G_OBJECT (mp));
303
 
 
304
 
        GDK_THREADS_LEAVE ();
305
 
 
306
 
        return FALSE;
307
 
}
308
 
 
309
 
static gboolean
310
 
buffering_end_signal_idle (RBPlayer *mp)
311
 
{
312
 
        GDK_THREADS_ENTER ();
313
 
 
314
 
        g_signal_emit (G_OBJECT (mp), rb_player_signals[BUFFERING_END], 0);
315
 
        g_object_unref (G_OBJECT (mp));
316
 
 
317
 
        GDK_THREADS_LEAVE ();
318
 
 
319
 
        return FALSE;
320
 
}
321
 
 
322
 
static gboolean
323
 
error_signal_idle (RBPlayerSignal *signal)
324
 
{
325
 
        g_signal_emit (G_OBJECT (signal->object),
326
 
                       rb_player_signals[ERROR], 0,
327
 
                       signal->error);
328
 
 
329
 
        /* close if not already closing */
330
 
        if (signal->object->priv->uri != NULL)
331
 
                rb_player_close (signal->object, NULL);
332
 
 
 
210
        gst_object_unref (GST_OBJECT (player->priv->playbin));
 
211
        player->priv->playbin = NULL;
 
212
}
 
213
 
 
214
static void
 
215
destroy_idle_signal (gpointer signal_pointer)
 
216
{
 
217
        RBPlayerSignal *signal = signal_pointer;
 
218
 
 
219
        if (signal->error)
 
220
                g_error_free (signal->error);
 
221
 
 
222
        if (signal->info) {
 
223
                g_value_unset (signal->info);
 
224
                g_free (signal->info);
 
225
        }
 
226
 
 
227
        if (signal->id != 0) {
 
228
                g_hash_table_remove (signal->object->priv->idle_info_ids,
 
229
                                     GUINT_TO_POINTER (signal->id));
 
230
        }
 
231
        
333
232
        g_object_unref (G_OBJECT (signal->object));
334
 
        g_error_free (signal->error);
335
233
        g_free (signal);
336
234
 
 
235
}
 
236
 
 
237
static gboolean
 
238
emit_signal_idle (RBPlayerSignal *signal)
 
239
{
 
240
        switch (signal->type) {
 
241
        case ERROR:
 
242
                g_signal_emit (G_OBJECT (signal->object),
 
243
                               rb_player_signals[ERROR], 0,
 
244
                               signal->error);
 
245
 
 
246
                /* close if not already closing */
 
247
                if (signal->object->priv->uri != NULL)
 
248
                        rb_player_close (signal->object, NULL);
 
249
 
 
250
                break;
 
251
 
 
252
        case EOS:
 
253
                g_signal_emit (G_OBJECT (signal->object), rb_player_signals[EOS], 0);
 
254
                signal->object->priv->idle_eos_id = 0;
 
255
                break;
 
256
 
 
257
        case INFO:
 
258
                g_signal_emit (G_OBJECT (signal->object),
 
259
                               rb_player_signals[INFO], 0,
 
260
                               signal->info_field, signal->info);
 
261
                break;
 
262
 
 
263
        case BUFFERING:
 
264
                g_signal_emit (G_OBJECT (signal->object),
 
265
                               rb_player_signals[BUFFERING], 0,
 
266
                               g_value_get_uint (signal->info));
 
267
                signal->object->priv->idle_buffering_id = 0;
 
268
                break;
 
269
        }
 
270
 
337
271
        return FALSE;
338
272
}
339
273
 
341
275
eos_cb (GstElement *element,
342
276
        RBPlayer *mp)
343
277
{
344
 
        g_object_ref (G_OBJECT (mp));
345
 
        g_idle_add ((GSourceFunc) eos_signal_idle, mp);
346
 
}
347
 
 
348
 
static void
349
 
rb_player_gst_signal_error (RBPlayer *mp, const char *msg)
350
 
{
351
278
        RBPlayerSignal *signal;
352
 
 
353
279
        signal = g_new0 (RBPlayerSignal, 1);
 
280
        signal->type = EOS;
354
281
        signal->object = mp;
355
 
        signal->error = g_error_new_literal (RB_PLAYER_ERROR,
356
 
                                             RB_PLAYER_ERROR_GENERAL,
357
 
                                             msg);
358
 
 
359
282
        g_object_ref (G_OBJECT (mp));
360
 
 
361
 
        g_idle_add ((GSourceFunc) error_signal_idle, signal);
 
283
        if (mp->priv->idle_eos_id)
 
284
                g_source_remove (mp->priv->idle_eos_id);
 
285
        mp->priv->idle_eos_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
 
286
                                                 (GSourceFunc) emit_signal_idle,
 
287
                                                 signal,
 
288
                                                 destroy_idle_signal);
362
289
}
363
290
 
364
291
static void
365
292
error_cb (GstElement *element,
366
293
          GstElement *source,
367
 
          GError *error,
 
294
          const GError *error,
368
295
          gchar *debug,
369
296
          RBPlayer *mp)
370
297
{
371
 
        rb_player_gst_signal_error (mp, error->message);
 
298
        int code;
 
299
        RBPlayerSignal *signal;
 
300
 
 
301
        /* the handler shouldn't get called with error=NULL, but sometimes it does */
 
302
        if (error == NULL)
 
303
                return;
 
304
 
 
305
        if ((error->domain == GST_CORE_ERROR)
 
306
            || (error->domain == GST_LIBRARY_ERROR)
 
307
            || (error->code == GST_RESOURCE_ERROR_BUSY)) {
 
308
                code = RB_PLAYER_ERROR_NO_AUDIO;
 
309
        } else {
 
310
                code = RB_PLAYER_ERROR_GENERAL;
 
311
        }
 
312
 
 
313
        /* If we're in a synchronous op, we can signal the error directly */
 
314
        if (mp->priv->can_signal_direct_error) {
 
315
                if (mp->priv->error) {
 
316
                        g_warning ("Overwriting previous error \"%s\" with new error \"%s\"",
 
317
                                   mp->priv->error->message,
 
318
                                   error->message);
 
319
                        g_error_free (mp->priv->error);
 
320
                }
 
321
                mp->priv->error = g_error_copy (error);
 
322
                return;
 
323
        }
 
324
 
 
325
        signal = g_new0 (RBPlayerSignal, 1);
 
326
        signal->type = ERROR;
 
327
        signal->object = mp;
 
328
        signal->error = g_error_new_literal (RB_PLAYER_ERROR,
 
329
                                             code,
 
330
                                             error->message);
 
331
 
 
332
        g_object_ref (G_OBJECT (mp));
 
333
 
 
334
        if (mp->priv->idle_error_id)
 
335
                g_source_remove (mp->priv->idle_error_id);
 
336
        mp->priv->idle_error_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
 
337
                                                   (GSourceFunc) emit_signal_idle,
 
338
                                                   signal,
 
339
                                                   destroy_idle_signal);
 
340
}
 
341
 
 
342
static void
 
343
process_tag (const GstTagList *list, const gchar *tag, RBPlayer *player)
 
344
{
 
345
        int count;
 
346
        RBMetaDataField field;
 
347
        RBPlayerSignal *signal;
 
348
        const GValue *val;
 
349
        GValue *newval;
 
350
 
 
351
        count = gst_tag_list_get_tag_size (list, tag);
 
352
        if (count < 1)
 
353
                return;
 
354
        
 
355
        /* only handle the subset of fields we use for iradio */
 
356
        if (!strcmp (tag, GST_TAG_TITLE))
 
357
                field = RB_METADATA_FIELD_TITLE;
 
358
        else if (!strcmp (tag, GST_TAG_GENRE))
 
359
                field = RB_METADATA_FIELD_GENRE;
 
360
        else if (!strcmp (tag, GST_TAG_COMMENT))
 
361
                field = RB_METADATA_FIELD_COMMENT;
 
362
        else if (!strcmp (tag, GST_TAG_BITRATE))
 
363
                field = RB_METADATA_FIELD_BITRATE;
 
364
        else
 
365
                return;
 
366
 
 
367
        /* of those, all except bitrate are strings */
 
368
        newval = g_new0 (GValue, 1);
 
369
        switch (field) {
 
370
        case RB_METADATA_FIELD_BITRATE:
 
371
                g_value_init (newval, G_TYPE_ULONG);
 
372
                break;
 
373
 
 
374
        case RB_METADATA_FIELD_TITLE:
 
375
        case RB_METADATA_FIELD_GENRE:
 
376
        case RB_METADATA_FIELD_COMMENT:
 
377
        default:
 
378
                g_value_init (newval, G_TYPE_STRING);
 
379
                break;
 
380
        }
 
381
        val = gst_tag_list_get_value_index (list, tag, 0);
 
382
        if (!g_value_transform (val, newval)) {
 
383
                rb_debug ("Could not transform tag value type %s into %s",
 
384
                          g_type_name (G_VALUE_TYPE (val)),
 
385
                          g_type_name (G_VALUE_TYPE (newval)));
 
386
                return;
 
387
        }
 
388
 
 
389
        signal = g_new0 (RBPlayerSignal, 1);
 
390
        signal->object = player;
 
391
        signal->info_field = field;
 
392
        signal->info = newval;
 
393
        signal->type = INFO;
 
394
        signal->id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
 
395
                                      (GSourceFunc) emit_signal_idle,
 
396
                                      signal,
 
397
                                      destroy_idle_signal);
 
398
 
 
399
        g_object_ref (G_OBJECT (player));
 
400
        g_hash_table_insert (player->priv->idle_info_ids, GUINT_TO_POINTER (signal->id), NULL);
 
401
}
 
402
 
 
403
static void
 
404
found_tag_cb (GObject *pipeline, GstElement *source, GstTagList *tags, RBPlayer *player)
 
405
{
 
406
        gst_tag_list_foreach (tags, (GstTagForeachFunc) process_tag, player);
 
407
}
 
408
 
 
409
static void
 
410
buffering_cb (GstElement *element, gint progress, RBPlayer *mp)
 
411
{
 
412
        RBPlayerSignal *signal;
 
413
 
 
414
        signal = g_new0 (RBPlayerSignal, 1);
 
415
        signal->type = BUFFERING;
 
416
 
 
417
        g_object_ref (G_OBJECT (mp));
 
418
        signal->object = mp;
 
419
 
 
420
        signal->info = g_new0 (GValue, 1);
 
421
        g_value_init (signal->info, G_TYPE_UINT);
 
422
        g_value_set_uint (signal->info, (guint)progress);
 
423
        if (mp->priv->idle_buffering_id)
 
424
                g_source_remove (mp->priv->idle_buffering_id);
 
425
        mp->priv->idle_buffering_id = g_idle_add ((GSourceFunc) emit_signal_idle, signal);
372
426
}
373
427
 
374
428
static gboolean
375
 
info_signal_idle (RBPlayerSignal *signal)
376
 
{
377
 
        g_signal_emit (G_OBJECT (signal->object),
378
 
                       rb_player_signals[INFO], 0,
379
 
                       signal->info_field, signal->info);
380
 
 
381
 
        g_object_unref (G_OBJECT (signal->object));
382
 
        g_free (signal->info);
383
 
        g_free (signal);
384
 
 
385
 
        return FALSE;
386
 
}
387
 
 
388
 
static void
389
 
deep_notify_cb (GstElement *element, GstElement *orig,
390
 
                GParamSpec *pspec, RBPlayer *player)
391
 
{
392
 
        if (!(pspec->flags & G_PARAM_READABLE)) return;
393
 
 
394
 
        if (strcmp (pspec->name, "iradio-title") == 0) {
395
 
                RBPlayerSignal *signal;
396
 
 
397
 
                rb_debug ("caught deep notify for iradio-title");
398
 
 
399
 
                signal = g_new0 (RBPlayerSignal, 1);
400
 
 
401
 
                signal->info_field = RB_METADATA_FIELD_TITLE;
402
 
                signal->info = g_new0 (GValue, 1);
403
 
                g_value_init (signal->info, G_TYPE_STRING); 
404
 
                g_object_get_property (G_OBJECT (orig), pspec->name, signal->info);
405
 
 
406
 
                signal->object = player;
407
 
 
408
 
                g_object_ref (G_OBJECT (player));
409
 
 
410
 
                g_idle_add ((GSourceFunc) info_signal_idle, signal);
411
 
                return;
412
 
        }
413
 
}
414
 
 
415
 
static void
416
 
queue_full_cb (GstQueue *queue,
417
 
               gpointer data)     
418
 
{
419
 
        RBPlayer *mp = RB_PLAYER (data);
420
 
 
421
 
        rb_debug ("caught queue full");
422
 
        g_signal_handlers_block_by_func (G_OBJECT (mp->priv->queue),
423
 
                                         G_CALLBACK (queue_full_cb),
424
 
                                         mp);
425
 
        if (gst_element_set_state (mp->priv->waiting_bin, GST_STATE_PLAYING) == GST_STATE_FAILURE) {
426
 
                rb_player_gst_signal_error (mp, _("Could not start pipeline playing"));
427
 
        } else {
428
 
                g_object_ref (G_OBJECT (mp));
429
 
                g_idle_add ((GSourceFunc) buffering_end_signal_idle, mp);
430
 
        }
431
 
}
432
 
 
433
 
static void
434
 
rb_player_construct (RBPlayer *mp,
435
 
                     gboolean iradio_mode,
436
 
                     gboolean audiocd_mode,
437
 
                     const char *uri,
438
 
                     GError **error)
439
 
{
440
 
        GstDParamManager *dpman;
 
429
rb_player_construct (RBPlayer *mp, GError **error)
 
430
{
441
431
        char *element_name = NULL;
442
 
 
443
 
#define MAKE_ELEMENT_OR_LOSE(NAME, NICE) G_STMT_START { \
444
 
        element_name = #NAME ;\
445
 
        rb_debug ("constructing element \"" #NICE "\""); \
446
 
        mp->priv->NICE = gst_element_factory_make (#NAME, #NICE); \
447
 
        if (!mp->priv->NICE) \
448
 
                goto missing_element; \
449
 
        } G_STMT_END
450
 
 
451
 
        /* The main playback pipeline for iradio, at the end this looks like:
452
 
         * { { src ! queue } ! { mad ! volume ! sink } }
453
 
         *
454
 
         * For local files, it just looks like:
455
 
         *  { src ! spider ! volume ! sink }
456
 
         */
457
 
        MAKE_ELEMENT_OR_LOSE(thread, pipeline);
458
 
        g_signal_connect_object (G_OBJECT (mp->priv->pipeline),
459
 
                                 "deep_notify",
460
 
                                 G_CALLBACK (deep_notify_cb),
 
432
        GstElement *sink, *fakesink;
 
433
 
 
434
        /* playbin */
 
435
        rb_debug ("constructing element \"playbin\"");
 
436
        mp->priv->playbin = gst_element_factory_make ("playbin", "playbin");
 
437
        if (mp->priv->playbin == NULL) {
 
438
                goto missing_element;
 
439
        }
 
440
 
 
441
        fakesink = gst_element_factory_make ("fakesink", "fakesink");
 
442
        g_object_set (G_OBJECT (mp->priv->playbin), "video-sink", fakesink, NULL);
 
443
 
 
444
        g_signal_connect_object (G_OBJECT (mp->priv->playbin),
 
445
                                 "found_tag",
 
446
                                 G_CALLBACK (found_tag_cb),
461
447
                                 mp, 0);
462
448
 
 
449
        mp->priv->buffering_signal_id =
 
450
                g_signal_connect_object (G_OBJECT (mp->priv->playbin),
 
451
                                         "buffering",
 
452
                                         G_CALLBACK (buffering_cb),
 
453
                                         mp, 0);
 
454
        
463
455
        mp->priv->error_signal_id =
464
 
                g_signal_connect_object (G_OBJECT (mp->priv->pipeline),
 
456
                g_signal_connect_object (G_OBJECT (mp->priv->playbin),
465
457
                                         "error",
466
458
                                         G_CALLBACK (error_cb),
467
459
                                         mp, 0);
468
460
 
469
 
        /* Construct the two threads */
470
 
        if (iradio_mode) {
471
 
                mp->priv->waiting_bin = gst_element_factory_make ("thread", "waiting_bin");
472
 
                mp->priv->srcthread = gst_element_factory_make ("thread", "srcthread");
473
 
                gst_bin_add_many (GST_BIN (mp->priv->pipeline),
474
 
                                  mp->priv->srcthread, mp->priv->waiting_bin, NULL);
475
 
        } else {
476
 
                mp->priv->waiting_bin = mp->priv->pipeline;
477
 
                mp->priv->srcthread = mp->priv->pipeline;
478
 
        }
479
 
 
480
 
        /* Construct elements */
481
 
 
482
 
        /* The source */
483
 
 
484
 
        if (audiocd_mode)
485
 
                element_name = "cdparanoia";
486
 
        else
487
 
                element_name = "gnomevfssrc";
488
 
        mp->priv->src = gst_element_factory_make (element_name, "src"); 
489
 
        if (mp->priv->src == NULL)
490
 
                goto missing_element;
491
 
        gst_bin_add (GST_BIN (mp->priv->srcthread), mp->priv->src);
492
 
 
493
 
#ifdef HAVE_AUDIOCD
494
 
        if (audiocd_mode) {
495
 
                g_object_set (G_OBJECT (mp->priv->src),
496
 
                              "paranoia-mode",
497
 
                              monkey_media_get_cd_playback_mode (),
498
 
                              NULL);
499
 
                g_object_set (G_OBJECT (mp->priv->src),
500
 
                              "location",
501
 
                              monkey_media_get_cd_drive (),
502
 
                              NULL);
503
 
        }
504
 
#endif
505
 
 
506
 
        rb_debug ("constructing queue");
507
 
        /* The queue */
508
 
        if (iradio_mode) {
509
 
                element_name = "queue";
510
 
                mp->priv->queue = gst_element_factory_make (element_name, element_name);
511
 
                if (mp->priv->queue == NULL)
512
 
                        goto missing_element;
513
 
                g_object_set (G_OBJECT (mp->priv->queue), "max-size-bytes", 64 * 1024, NULL);
514
 
                g_signal_connect_object (G_OBJECT (mp->priv->queue), "overrun",
515
 
                                         G_CALLBACK (queue_full_cb), mp, 0);
516
 
                gst_bin_add (GST_BIN (mp->priv->srcthread), mp->priv->queue);
517
 
        }
518
 
 
519
 
        MAKE_ELEMENT_OR_LOSE(typefind, typefind);
520
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->typefind);
521
 
 
522
 
        MAKE_ELEMENT_OR_LOSE(spider, decoder);
523
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->decoder);
524
 
 
525
 
        MAKE_ELEMENT_OR_LOSE(volume, volume);
526
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->volume);
527
 
        dpman = gst_dpman_get_manager (mp->priv->volume);
528
 
        mp->priv->volume_dpmanager = dpman;
529
 
        gst_dpman_set_mode (dpman, "synchronous");
530
 
        mp->priv->volume_dparam = gst_dpsmooth_new (G_TYPE_DOUBLE);
531
 
        g_assert (mp->priv->volume_dparam != NULL);
532
 
        gst_dpman_attach_dparam (dpman, "volume", mp->priv->volume_dparam);
533
 
 
534
 
        MAKE_ELEMENT_OR_LOSE(audioconvert, audioconvert);
535
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->audioconvert);
536
 
 
537
 
        MAKE_ELEMENT_OR_LOSE(audioscale, audioscale);
538
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->audioscale);
539
 
 
540
461
        /* Output sink */
541
 
        mp->priv->sink = gst_gconf_get_default_audio_sink ();
542
 
        if (mp->priv->sink == NULL) {
 
462
        sink = gst_gconf_get_default_audio_sink ();
 
463
        if (sink == NULL) {
543
464
                g_set_error (error,
544
465
                             RB_PLAYER_ERROR,
545
466
                             RB_PLAYER_ERROR_NO_AUDIO,
546
467
                             _("Could not create audio output element; check your settings"));
547
 
                gst_object_unref (GST_OBJECT (mp->priv->pipeline));
548
 
                mp->priv->pipeline = NULL;
549
 
                return;
 
468
                rb_player_gst_free_playbin (mp);
 
469
                return FALSE;
550
470
        }
551
 
        gst_bin_add (GST_BIN (mp->priv->waiting_bin), mp->priv->sink);
552
 
 
553
 
        gst_element_link_many (mp->priv->decoder, mp->priv->volume, mp->priv->audioconvert, mp->priv->audioscale, mp->priv->sink, NULL);
554
 
        if (iradio_mode)
555
 
                gst_element_link_many (mp->priv->src, mp->priv->queue, mp->priv->typefind, mp->priv->decoder, NULL);
556
 
        else
557
 
                gst_element_link_many (mp->priv->src, mp->priv->typefind, mp->priv->decoder, NULL);
558
 
 
559
 
        g_signal_connect_object (G_OBJECT (mp->priv->sink), "eos",
 
471
 
 
472
        g_object_set (G_OBJECT (mp->priv->playbin), "audio-sink", sink, NULL);
 
473
        g_signal_connect_object (G_OBJECT (mp->priv->playbin), "eos",
560
474
                                 G_CALLBACK (eos_cb), mp, 0);
561
475
 
562
476
        if (mp->priv->cur_volume > 1.0)
563
477
                mp->priv->cur_volume = 1.0;
564
478
        if (mp->priv->cur_volume < 0.0)
565
479
                mp->priv->cur_volume = 0;
566
 
        g_object_set (G_OBJECT (mp->priv->volume_dparam),
567
 
                      "value_double", mp->priv->cur_volume,
568
 
                      NULL);
 
480
        rb_player_set_volume (mp, mp->priv->cur_volume);
569
481
 
570
 
        if (mp->priv->timer)
571
 
                g_timer_destroy (mp->priv->timer);
572
 
        mp->priv->timer = g_timer_new ();
573
 
        g_timer_stop (mp->priv->timer);
574
 
        g_timer_reset (mp->priv->timer);
575
 
        mp->priv->timer_add = 0;
576
482
        rb_debug ("pipeline construction complete");
577
 
        return;
 
483
        return TRUE;
578
484
missing_element:
579
485
        {
580
486
                char *err = g_strdup_printf (_("Failed to create %s element; check your installation"),
584
490
                             RB_PLAYER_ERROR_GENERAL,
585
491
                             err);
586
492
                g_free (err);
587
 
                rb_player_gst_free_pipeline (mp);
 
493
                rb_player_gst_free_playbin (mp);
 
494
                return FALSE;
588
495
        }
589
496
}
590
497
 
604
511
                return NULL;
605
512
        }
606
513
 
607
 
        mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER, NULL));
 
514
        mp = RB_PLAYER (g_object_new (RB_TYPE_PLAYER, NULL, NULL));
608
515
 
609
516
        return mp;
610
517
}
620
527
}
621
528
 
622
529
static gboolean
623
 
rb_player_sync_pipeline (RBPlayer *mp, gboolean iradio_mode, GError **error)
 
530
rb_player_sync_pipeline (RBPlayer *mp)
624
531
{
625
 
        static gint may_pause = -1;
626
 
  
627
532
        rb_debug ("syncing pipeline");
628
533
        if (mp->priv->playing) {
629
 
                if (iradio_mode) {
630
 
                        rb_debug ("beginning buffering");
631
 
                        g_object_ref (G_OBJECT (mp));
632
 
                        g_idle_add ((GSourceFunc) buffering_begin_signal_idle, mp);
633
 
                        if (gst_element_set_state (mp->priv->srcthread,
634
 
                                                   GST_STATE_PLAYING) == GST_STATE_FAILURE) {
635
 
                                g_set_error (error,
636
 
                                             RB_PLAYER_ERROR,
637
 
                                             RB_PLAYER_ERROR_GENERAL,
638
 
                                             _("Could not start pipeline playing"));
639
 
                                return FALSE;
640
 
                        }
641
 
                } else {
642
 
                        rb_debug ("PLAYING pipeline");
643
 
                        if (gst_element_set_state (mp->priv->pipeline,
644
 
                                                   GST_STATE_PLAYING) == GST_STATE_FAILURE) {
645
 
                                g_set_error (error,
646
 
                                             RB_PLAYER_ERROR,
647
 
                                             RB_PLAYER_ERROR_GENERAL,
648
 
                                             _("Could not start pipeline playing"));
649
 
                                return FALSE;
650
 
                        }                               
 
534
                rb_debug ("PLAYING pipeline");
 
535
                if (gst_element_set_state (mp->priv->playbin,
 
536
                                           GST_STATE_PLAYING) == GST_STATE_FAILURE) {
 
537
                        return FALSE;
651
538
                }
652
 
                g_timer_start (mp->priv->timer);
653
539
        } else {
654
 
                /* get correct gst version */
655
 
                if (may_pause == -1) {
656
 
                        guint major, minor, micro;
657
 
 
658
 
                        rb_debug ("decoding gst version to check if we may free the audio sink");
659
 
                        gst_version (&major, &minor, &micro);
660
 
                        /* this makes sure someone removes this later on */
661
 
                        g_assert (major == 0);
662
 
                        g_assert (minor == 8);
663
 
                        if (micro > 1)
664
 
                                may_pause = 1;
665
 
                        else
666
 
                                may_pause = 0;
667
 
                }
668
 
                
669
540
                rb_debug ("PAUSING pipeline");
670
 
                if (gst_element_set_state (mp->priv->pipeline,
 
541
                if (gst_element_set_state (mp->priv->playbin,
671
542
                                           GST_STATE_PAUSED) == GST_STATE_FAILURE) {
672
 
                        g_set_error (error,
673
 
                                     RB_PLAYER_ERROR,
674
 
                                     RB_PLAYER_ERROR_GENERAL,
675
 
                                     _("Could not pause playback"));
676
543
                        return FALSE;
677
544
                }
678
 
                        
679
 
                if (may_pause == 1) {
680
 
                        rb_debug ("setting sink to NULL");
681
 
                        if (gst_element_set_state (mp->priv->sink, GST_STATE_NULL) != GST_STATE_SUCCESS) {
682
 
                                g_set_error (error,
683
 
                                             RB_PLAYER_ERROR,
684
 
                                             RB_PLAYER_ERROR_GENERAL,
685
 
                                             _("Could not close output sink"));
686
 
                                return FALSE;
687
 
                        }
688
 
                }
689
545
        }
690
546
        return TRUE;
691
547
}
692
548
 
693
 
void
 
549
/* Start a sequence of synchronous GStreamer operations in which we
 
550
 * can receive an error signal.
 
551
 */
 
552
static void
 
553
begin_gstreamer_operation (RBPlayer *mp)
 
554
{
 
555
        g_assert (mp->priv->error == NULL);
 
556
        mp->priv->can_signal_direct_error = TRUE;
 
557
}
 
558
 
 
559
/* End a sequence of synchronous operations and propagate any
 
560
 * error from the sequence into error.
 
561
 */
 
562
static void
 
563
end_gstreamer_operation (RBPlayer *mp, gboolean op_failed, GError **error)
 
564
{
 
565
        mp->priv->can_signal_direct_error = FALSE;
 
566
        if (mp->priv->error) {
 
567
                g_propagate_error (error, mp->priv->error);
 
568
                mp->priv->error = NULL;
 
569
        } else if (op_failed) {
 
570
                g_set_error (error,
 
571
                             RB_PLAYER_ERROR,
 
572
                             RB_PLAYER_ERROR_GENERAL,
 
573
                             _("Unknown playback error"));
 
574
        }
 
575
}
 
576
 
 
577
static void
 
578
cdda_got_source_cb (GObject *object, GParamSpec *pspec, char *uri)
 
579
{
 
580
        GstElement *source;
 
581
 
 
582
        gst_element_get (GST_ELEMENT (object), "source", &source, NULL);
 
583
        rb_debug ("got source %p", source);
 
584
        if (source) {
 
585
                g_signal_handlers_disconnect_by_func (object, cdda_got_source_cb, uri);
 
586
 
 
587
                g_object_set (G_OBJECT (source), "device", uri, NULL);
 
588
                g_free (uri);
 
589
        }
 
590
}
 
591
 
 
592
gboolean
694
593
rb_player_open (RBPlayer *mp,
695
594
                const char *uri,
696
595
                GError **error)
697
596
{
698
 
        gboolean audiocd_mode = uri && g_str_has_prefix (uri, "audiocd://");
699
 
        gboolean iradio_mode = uri && g_str_has_prefix (uri, "http://");
700
 
 
701
 
        g_return_if_fail (RB_IS_PLAYER (mp));
702
 
 
703
 
        if (mp->priv->pipeline) {
704
 
                gst_element_set_state (mp->priv->pipeline,
705
 
                                       GST_STATE_NULL);
706
 
                rb_player_gst_free_pipeline (mp);
 
597
        g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
 
598
 
 
599
        if (mp->priv->playbin == NULL) {
 
600
                if (!rb_player_construct (mp, error))
 
601
                        return FALSE;
707
602
        }
708
603
 
 
604
        g_assert (mp->priv->playbin != NULL);
 
605
 
709
606
        g_free (mp->priv->uri);
710
607
        mp->priv->uri = NULL;
711
608
 
712
609
        if (uri == NULL) {
713
610
                mp->priv->playing = FALSE;
714
 
                return;
715
 
        }
716
 
 
717
 
        rb_player_construct (mp, iradio_mode, audiocd_mode, uri, error);
718
 
        if (error && *error)
719
 
                return;
720
 
 
721
 
#ifdef HAVE_AUDIOCD
722
 
        if (audiocd_mode)
723
 
        {
724
 
                GstEvent *event;
725
 
                int tracknum;
726
 
 
727
 
                if (!mp->priv->cd) {
728
 
                        g_set_error (error,
729
 
                                     RB_PLAYER_ERROR,
730
 
                                     RB_PLAYER_ERROR_INTERNAL,
731
 
                                     _("No AudioCD support; check your settings"));
732
 
                        return;
733
 
                }
734
 
 
735
 
                tracknum = atoi (uri + 10);
736
 
 
737
 
                if (!monkey_media_audio_cd_have_track (mp->priv->cd, tracknum, error)) {
738
 
                        return;
739
 
                }
740
 
 
741
 
                gst_element_set_state (mp->priv->pipeline, GST_STATE_PAUSED);
742
 
 
743
 
                /* 7 is track format */
744
 
                event = gst_event_new_seek (7 |
745
 
                                            GST_SEEK_METHOD_SET |
746
 
                                            GST_SEEK_FLAG_FLUSH, tracknum);
747
 
                gst_element_send_event (mp->priv->sink, event);
748
 
        } else
749
 
#endif    
750
 
        {
751
 
 
752
 
                /* Internet radio support */
753
 
                g_object_set (G_OBJECT (mp->priv->src),
754
 
                              "iradio-mode", iradio_mode, NULL);
755
 
                
756
 
                g_object_set (G_OBJECT (mp->priv->src),
757
 
                              "location", uri, NULL);
758
 
        }
759
 
        mp->priv->iradio_mode = iradio_mode;
760
 
        
 
611
                return TRUE;
 
612
        }
 
613
 
 
614
 
 
615
        begin_gstreamer_operation (mp);
761
616
        mp->priv->uri = g_strdup (uri);
762
617
 
763
 
        g_timer_stop (mp->priv->timer);
764
 
        g_timer_reset (mp->priv->timer);
765
 
        mp->priv->timer_add = 0;
766
 
 
767
 
        if (!rb_player_sync_pipeline (mp, iradio_mode, error)) {
 
618
        if (g_str_has_prefix (uri, "cdda://")) {
 
619
                gchar *copy, *temp, *split;
 
620
                int l = strlen ("cdda://");
 
621
 
 
622
                copy = g_strdup (uri);
 
623
                split = g_utf8_strrchr (copy + l, -1, ':');
 
624
 
 
625
                if (split == NULL) {
 
626
                        /* invalid URI, it doesn't contain a ':' */
 
627
                        end_gstreamer_operation (mp, TRUE, error);
 
628
                        return FALSE;
 
629
                }
 
630
 
 
631
                temp = g_strdup_printf ("cdda://%s", split + 1);
 
632
                g_object_set (G_OBJECT (mp->priv->playbin), "uri", temp, NULL);
 
633
                g_free (temp);
 
634
 
 
635
                *split = 0;
 
636
                temp = g_strdup (copy + l);
 
637
                g_signal_connect (G_OBJECT (mp->priv->playbin),
 
638
                                  "notify::source",
 
639
                                  G_CALLBACK (cdda_got_source_cb),
 
640
                                  temp);
 
641
                g_free (copy);
 
642
        } else {
 
643
                g_object_set (G_OBJECT (mp->priv->playbin), "uri", uri, NULL);
 
644
        }
 
645
 
 
646
        if (!rb_player_sync_pipeline (mp)) {
 
647
                end_gstreamer_operation (mp, TRUE, error);
768
648
                rb_player_close (mp, NULL);
 
649
                return FALSE;
769
650
        }
770
 
}
771
 
 
772
 
void
 
651
        end_gstreamer_operation (mp, FALSE, error);
 
652
        return TRUE;
 
653
}
 
654
 
 
655
static void
 
656
remove_idle_source (gpointer key, gpointer value, gpointer user_data)
 
657
{
 
658
        guint id = GPOINTER_TO_UINT (key);
 
659
 
 
660
        g_source_remove (id);
 
661
}
 
662
 
 
663
gboolean
773
664
rb_player_close (RBPlayer *mp, GError **error)
774
665
{
775
 
        g_return_if_fail (RB_IS_PLAYER (mp));
 
666
        gboolean ret;
 
667
        g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
776
668
 
777
669
        mp->priv->playing = FALSE;
778
670
 
779
671
        g_free (mp->priv->uri);
780
672
        mp->priv->uri = NULL;
781
673
 
782
 
        if (mp->priv->pipeline == NULL)
783
 
                return;
784
 
 
785
 
        if (gst_element_set_state (mp->priv->pipeline,
786
 
                                   GST_STATE_NULL) != GST_STATE_SUCCESS) {
787
 
                g_set_error (error,
788
 
                             RB_PLAYER_ERROR,
789
 
                             RB_PLAYER_ERROR_GENERAL,
790
 
                             _("Failed to close audio output sink"));
791
 
        }
792
 
 
793
 
        gst_object_unref (GST_OBJECT (mp->priv->pipeline));
794
 
        mp->priv->pipeline = NULL;
 
674
        if (mp->priv->idle_eos_id != 0) {
 
675
                g_source_remove (mp->priv->idle_eos_id);
 
676
                mp->priv->idle_eos_id = 0;
 
677
        }
 
678
        if (mp->priv->idle_error_id != 0) {
 
679
                g_source_remove (mp->priv->idle_error_id);
 
680
                mp->priv->idle_error_id = 0;
 
681
        }
 
682
        if (mp->priv->idle_buffering_id != 0) {
 
683
                g_source_remove (mp->priv->idle_buffering_id);
 
684
                mp->priv->idle_buffering_id = 0;
 
685
        }
 
686
        g_hash_table_foreach (mp->priv->idle_info_ids, remove_idle_source, NULL);
 
687
 
 
688
        if (mp->priv->playbin == NULL)
 
689
                return TRUE;
 
690
 
 
691
        begin_gstreamer_operation (mp);
 
692
        ret = gst_element_set_state (mp->priv->playbin, GST_STATE_READY) == GST_STATE_SUCCESS;
 
693
        end_gstreamer_operation (mp, !ret, error);
 
694
        return ret;
795
695
}
796
696
 
797
697
gboolean
802
702
        return mp->priv->uri != NULL;
803
703
}
804
704
 
805
 
void
 
705
gboolean
806
706
rb_player_play (RBPlayer *mp, GError **error)
807
707
{
808
 
        g_return_if_fail (RB_IS_PLAYER (mp));
 
708
        gboolean ret;
 
709
        g_return_val_if_fail (RB_IS_PLAYER (mp), TRUE);
809
710
 
810
711
        mp->priv->playing = TRUE;
811
712
 
812
 
        g_return_if_fail (mp->priv->pipeline != NULL);
 
713
        g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
813
714
 
814
 
        rb_player_sync_pipeline (mp, mp->priv->iradio_mode, error);
 
715
        begin_gstreamer_operation (mp);
 
716
        ret = rb_player_sync_pipeline (mp);
 
717
        end_gstreamer_operation (mp, !ret, error);
 
718
        return ret;
815
719
}
816
720
 
817
721
void
824
728
 
825
729
        mp->priv->playing = FALSE;
826
730
 
827
 
        g_return_if_fail (mp->priv->pipeline != NULL);
828
 
 
829
 
        mp->priv->timer_add += floor (g_timer_elapsed (mp->priv->timer, NULL) + 0.5);
830
 
        g_timer_stop (mp->priv->timer);
831
 
        g_timer_reset (mp->priv->timer);
832
 
 
833
 
        rb_player_sync_pipeline (mp, mp->priv->iradio_mode, NULL);
 
731
        g_return_if_fail (mp->priv->playbin != NULL);
 
732
 
 
733
        rb_player_sync_pipeline (mp);
834
734
}
835
735
 
836
736
gboolean
876
776
        
877
777
        rb_debug ("Scale : %f New volume : %f", scale, mp->priv->cur_volume * scale);
878
778
 
879
 
        if (mp->priv->pipeline != NULL) {
880
 
                g_object_set (G_OBJECT (mp->priv->volume_dparam),
881
 
                              "value_double",
882
 
                              mp->priv->cur_volume * scale,
883
 
                              NULL);
 
779
        if (mp->priv->playbin != NULL) {
 
780
                GParamSpec *volume_pspec;
 
781
                GValue val;
 
782
                
 
783
                volume_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (mp->priv->playbin),
 
784
                                                             "volume");
 
785
                g_value_init (&val, G_TYPE_DOUBLE);
 
786
                
 
787
                g_value_set_double (&val, mp->priv->cur_volume * scale);
 
788
                if (g_param_value_validate (volume_pspec, &val))
 
789
                        rb_debug ("replay gain too high, reducing value to %f", g_value_get_double (&val));
 
790
        
 
791
                g_object_set_property (G_OBJECT (mp->priv->playbin), "volume", &val);
 
792
                g_value_unset (&val);
884
793
        }
885
794
}
886
795
 
891
800
        g_return_if_fail (RB_IS_PLAYER (mp));
892
801
        g_return_if_fail (volume >= 0.0 && volume <= 1.0);
893
802
 
894
 
        if (mp->priv->pipeline != NULL) {
895
 
                g_object_set (G_OBJECT (mp->priv->volume_dparam),
896
 
                              "value_double",
 
803
        if (mp->priv->playbin != NULL) {
 
804
                g_object_set (G_OBJECT (mp->priv->playbin),
 
805
                              "volume",
897
806
                              volume,
898
807
                              NULL);
899
808
        }
913
822
rb_player_seekable (RBPlayer *mp)
914
823
{
915
824
        g_return_val_if_fail (RB_IS_PLAYER (mp), FALSE);
916
 
        g_return_val_if_fail (mp->priv->pipeline != NULL, FALSE);
 
825
        g_return_val_if_fail (mp->priv->playbin != NULL, FALSE);
917
826
 
918
827
        /* FIXME we're lying here, no idea how to fix this though, without trying
919
828
         * a seek which might disrupt playback */
921
830
}
922
831
 
923
832
void
924
 
rb_player_set_time (RBPlayer *mp,
925
 
                              long time)
 
833
rb_player_set_time (RBPlayer *mp, long time)
926
834
{
927
 
        GstEvent *event;
928
 
 
929
835
        g_return_if_fail (RB_IS_PLAYER (mp));
930
836
        g_return_if_fail (time >= 0);
931
837
 
932
 
        g_return_if_fail (mp->priv->pipeline != NULL);
933
 
 
934
 
        gst_element_set_state (mp->priv->pipeline, GST_STATE_PAUSED);
935
 
 
936
 
        event = gst_event_new_seek (GST_FORMAT_TIME |
937
 
                                    GST_SEEK_METHOD_SET |
938
 
                                    GST_SEEK_FLAG_FLUSH, time * GST_SECOND);
939
 
        gst_element_send_event (mp->priv->sink, event);
940
 
 
 
838
        g_return_if_fail (mp->priv->playbin != NULL);
 
839
 
 
840
        gst_element_set_state (mp->priv->playbin, GST_STATE_PAUSED);
 
841
 
 
842
#ifdef WITH_DAAP_SUPPORT
 
843
        /* FIXME?
 
844
         * This is sorta hack/sorta best way to do it.
 
845
         * If we set up the daapsrc to do regular GStreamer seeking,
 
846
         * GStreamer goes ape-shit and tries to seek all over the 
 
847
         * place (typefinding), which can cause iTunes to return errors
 
848
         * (probably cause we're requesting the same file too often)
 
849
         *
 
850
         * So, we do it this way.  Doesn't that suck?
 
851
         */
 
852
        if (mp->priv->uri && g_strncasecmp (mp->priv->uri, "daap://", 7) == 0) {
 
853
                rb_daap_src_set_time (time);
 
854
        } else {
 
855
#endif
 
856
        gst_element_seek (mp->priv->playbin, 
 
857
                          GST_FORMAT_TIME 
 
858
                          | GST_SEEK_METHOD_SET 
 
859
                          | GST_SEEK_FLAG_FLUSH, 
 
860
                          time * GST_SECOND);
 
861
#ifdef WITH_DAAP_SUPPORT
 
862
        }
 
863
#endif
941
864
        if (mp->priv->playing)
942
 
                gst_element_set_state (mp->priv->pipeline, GST_STATE_PLAYING);
943
 
 
944
 
        g_timer_reset (mp->priv->timer);
945
 
        mp->priv->timer_add = time;
 
865
                gst_element_set_state (mp->priv->playbin, GST_STATE_PLAYING);
946
866
}
947
867
 
948
868
long
950
870
{
951
871
        g_return_val_if_fail (RB_IS_PLAYER (mp), -1);
952
872
 
953
 
        if (mp->priv->pipeline != NULL)
954
 
                return (long) floor (g_timer_elapsed (mp->priv->timer, NULL) + 0.5) + mp->priv->timer_add;
955
 
        else
 
873
        if (mp->priv->playbin != NULL) {
 
874
                gint64 gst_position;
 
875
                glong ret = 0;
 
876
 
 
877
                GstFormat fmt = GST_FORMAT_TIME;
 
878
                gst_element_query (mp->priv->playbin, GST_QUERY_POSITION, &fmt, &gst_position);
 
879
                ret = (glong) (gst_position / (1000*1000*1000));
 
880
 
 
881
#ifdef WITH_DAAP_SUPPORT
 
882
                if (mp->priv->uri && g_strncasecmp (mp->priv->uri, "daap://", 7) == 0) {
 
883
                        ret += rb_daap_src_get_time ();
 
884
                }
 
885
#endif
 
886
 
 
887
                return ret;
 
888
        } else
956
889
                return -1;
957
890
}