~ubuntu-branches/ubuntu/saucy/clementine/saucy

« back to all changes in this revision

Viewing changes to src/engines/gstenginepipeline.cpp

  • Committer: Package Import Robot
  • Author(s): Thomas PIERSON
  • Date: 2012-01-01 20:43:39 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120101204339-lsb6nndwhfy05sde
Tags: 1.0.1+dfsg-1
New upstream release. (Closes: #653926, #651611, #657391)

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
#include <limits>
19
19
 
 
20
#include "bufferconsumer.h"
 
21
#include "config.h"
20
22
#include "gstelementdeleter.h"
 
23
#include "gstengine.h"
21
24
#include "gstenginepipeline.h"
22
 
#include "gstengine.h"
23
 
#include "bufferconsumer.h"
24
 
 
25
 
#include <QDebug>
 
25
#include "core/logging.h"
 
26
#include "core/utilities.h"
 
27
#include "internet/internetmodel.h"
 
28
 
 
29
#ifdef HAVE_SPOTIFY
 
30
#  include "internet/spotifyserver.h"
 
31
#  include "internet/spotifyservice.h"
 
32
#endif
 
33
 
26
34
#include <QtConcurrentRun>
27
35
 
28
36
const int GstEnginePipeline::kGstStateTimeoutNanosecs = 10000000;
44
52
    sink_(GstEngine::kAutoSink),
45
53
    segment_start_(0),
46
54
    segment_start_received_(false),
 
55
    emit_track_ended_on_segment_start_(false),
47
56
    eq_enabled_(false),
48
57
    eq_preamp_(0),
49
58
    rg_enabled_(false),
65
74
    pipeline_(NULL),
66
75
    uridecodebin_(NULL),
67
76
    audiobin_(NULL),
 
77
    queue_(NULL),
68
78
    audioconvert_(NULL),
69
79
    rgvolume_(NULL),
70
80
    rglimiter_(NULL),
102
112
bool GstEnginePipeline::ReplaceDecodeBin(GstElement* new_bin) {
103
113
  if (!new_bin) return false;
104
114
 
105
 
  // Destroy the old one, if any
 
115
  // Destroy the old elements if they are set
 
116
  // Note that the caller to this function MUST schedule the old uridecodebin_
 
117
  // for deletion in the main thread.
106
118
  if (uridecodebin_) {
107
119
    gst_bin_remove(GST_BIN(pipeline_), uridecodebin_);
108
 
 
109
 
    // Note that the caller to this function MUST schedule the old bin for
110
 
    // deletion in the main thread
111
120
  }
112
121
 
113
122
  uridecodebin_ = new_bin;
120
129
}
121
130
 
122
131
bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
123
 
  GstElement* new_bin = engine_->CreateElement("uridecodebin");
124
 
  g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), NULL);
125
 
  g_object_set(G_OBJECT(new_bin), "buffer-duration", buffer_duration_nanosec_, NULL);
126
 
  g_object_set(G_OBJECT(new_bin), "download", true, NULL);
127
 
  g_object_set(G_OBJECT(new_bin), "use-buffering", true, NULL);
128
 
  g_signal_connect(G_OBJECT(new_bin), "drained", G_CALLBACK(SourceDrainedCallback), this);
129
 
  g_signal_connect(G_OBJECT(new_bin), "pad-added", G_CALLBACK(NewPadCallback), this);
 
132
  GstElement* new_bin = NULL;
 
133
 
 
134
  if (url.scheme() == "spotify") {
 
135
    #ifdef HAVE_SPOTIFY
 
136
      new_bin = gst_bin_new("spotify_bin");
 
137
 
 
138
      // Create elements
 
139
      GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
 
140
      GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
 
141
      if (!src || !gdp)
 
142
        return false;
 
143
 
 
144
      // Pick a port number
 
145
      const int port = Utilities::PickUnusedPort();
 
146
      g_object_set(G_OBJECT(src), "host", "127.0.0.1", NULL);
 
147
      g_object_set(G_OBJECT(src), "port", port, NULL);
 
148
 
 
149
      // Link the elements
 
150
      gst_element_link(src, gdp);
 
151
 
 
152
      // Add a ghost pad
 
153
      GstPad* pad = gst_element_get_static_pad(gdp, "src");
 
154
      gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
 
155
      gst_object_unref(GST_OBJECT(pad));
 
156
 
 
157
      // Tell spotify to start sending data to us.
 
158
      InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(url.toString(), port);
 
159
    #else // HAVE_SPOTIFY
 
160
      qLog(Error) << "Tried to play a spotify:// url, but spotify support is not compiled in";
 
161
      return false;
 
162
    #endif
 
163
  } else {
 
164
    new_bin = engine_->CreateElement("uridecodebin");
 
165
    g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), NULL);
 
166
    g_object_set(G_OBJECT(new_bin), "buffer-duration", buffer_duration_nanosec_, NULL);
 
167
    g_object_set(G_OBJECT(new_bin), "download", true, NULL);
 
168
    g_object_set(G_OBJECT(new_bin), "use-buffering", true, NULL);
 
169
    g_signal_connect(G_OBJECT(new_bin), "drained", G_CALLBACK(SourceDrainedCallback), this);
 
170
    g_signal_connect(G_OBJECT(new_bin), "pad-added", G_CALLBACK(NewPadCallback), this);
 
171
    g_signal_connect(G_OBJECT(new_bin), "notify::source", G_CALLBACK(SourceSetupCallback), this);
 
172
  }
 
173
 
130
174
  return ReplaceDecodeBin(new_bin);
131
175
}
132
176
 
140
184
    int code = error->code;
141
185
    g_error_free(error);
142
186
 
143
 
    qWarning() << message;
 
187
    qLog(Warning) << message;
144
188
    emit Error(id(), message, domain, code);
145
189
 
146
190
    return NULL;
155
199
  //   uri decode bin -> audio bin
156
200
  // The uri decode bin is a gstreamer builtin that automatically picks the
157
201
  // right type of source and decoder for the URI.
 
202
 
158
203
  // The audio bin gets created here and contains:
159
 
  //   audioconvert -> rgvolume -> rglimiter -> equalizer_preamp -> equalizer ->
160
 
  //   volume -> audioscale -> audioconvert -> audiosink
 
204
  //   queue ! audioconvert ! <caps32>
 
205
  //         ! ( rgvolume ! rglimiter ! audioconvert2 ) ! tee
 
206
  // rgvolume and rglimiter are only created when replaygain is enabled.
 
207
 
 
208
  // After the tee the pipeline splits.  One split is converted to 16-bit int
 
209
  // samples for the scope, the other is kept as float32 and sent to the
 
210
  // speaker.
 
211
  //   tee1 ! probe_queue ! probe_converter ! <caps16> ! probe_sink
 
212
  //   tee2 ! audio_queue ! equalizer_preamp ! equalizer ! volume ! audioscale
 
213
  //        ! convert ! audiosink
161
214
 
162
215
  // Audio bin
163
216
  audiobin_ = gst_bin_new("audiobin");
164
217
  gst_bin_add(GST_BIN(pipeline_), audiobin_);
165
218
 
 
219
  // Create the sink
166
220
  if (!(audiosink_ = engine_->CreateElement(sink_, audiobin_)))
167
221
    return false;
168
222
 
169
223
  if (GstEngine::DoesThisSinkSupportChangingTheOutputDeviceToAUserEditableString(sink_) && !device_.isEmpty())
170
224
    g_object_set(G_OBJECT(audiosink_), "device", device_.toUtf8().constData(), NULL);
171
225
 
172
 
  if (!(equalizer_preamp_ = engine_->CreateElement("volume", audiobin_))) { return false; }
173
 
  if (!(equalizer_ = engine_->CreateElement("equalizer-nbands", audiobin_))) { return false; }
174
 
  if (!(audioconvert_ = engine_->CreateElement("audioconvert", audiobin_))) { return false; }
175
 
  if (!(volume_ = engine_->CreateElement("volume", audiobin_))) { return false; }
176
 
  if (!(audioscale_ = engine_->CreateElement("audioresample", audiobin_))) { return false; }
177
 
  GstElement* scope_element = audioconvert_;
 
226
  // Create all the other elements
 
227
  GstElement *tee, *probe_queue, *probe_converter, *probe_sink, *audio_queue,
 
228
             *convert;
 
229
 
 
230
  queue_            = engine_->CreateElement("queue",            audiobin_);
 
231
  audioconvert_     = engine_->CreateElement("audioconvert",     audiobin_);
 
232
  tee               = engine_->CreateElement("tee",              audiobin_);
 
233
 
 
234
  probe_queue       = engine_->CreateElement("queue",            audiobin_);
 
235
  probe_converter   = engine_->CreateElement("audioconvert",     audiobin_);
 
236
  probe_sink        = engine_->CreateElement("fakesink",         audiobin_);
 
237
 
 
238
  audio_queue       = engine_->CreateElement("queue",            audiobin_);
 
239
  equalizer_preamp_ = engine_->CreateElement("volume",           audiobin_);
 
240
  equalizer_        = engine_->CreateElement("equalizer-nbands", audiobin_);
 
241
  volume_           = engine_->CreateElement("volume",           audiobin_);
 
242
  audioscale_       = engine_->CreateElement("audioresample",    audiobin_);
 
243
  convert           = engine_->CreateElement("audioconvert",     audiobin_);
 
244
 
 
245
  if (!queue_ || !audioconvert_ || !tee || !probe_queue || !probe_converter ||
 
246
      !probe_sink || !audio_queue || !equalizer_preamp_ || !equalizer_ ||
 
247
      !volume_ || !audioscale_ || !convert) {
 
248
    return false;
 
249
  }
 
250
 
 
251
  // Create the replaygain elements if it's enabled.  event_probe is the
 
252
  // audioconvert element we attach the probe to, which will change depending
 
253
  // on whether replaygain is enabled.  convert_sink is the element after the
 
254
  // first audioconvert, which again will change.
 
255
  GstElement* event_probe = audioconvert_;
 
256
  GstElement* convert_sink = tee;
178
257
 
179
258
  if (rg_enabled_) {
180
 
    if (!(rgvolume_ = engine_->CreateElement("rgvolume", audiobin_))) { return false; }
181
 
    if (!(rglimiter_ = engine_->CreateElement("rglimiter", audiobin_))) { return false; }
182
 
    if (!(audioconvert2_ = engine_->CreateElement("audioconvert", audiobin_))) { return false; }
183
 
    scope_element = audioconvert2_;
 
259
    rgvolume_      = engine_->CreateElement("rgvolume",     audiobin_);
 
260
    rglimiter_     = engine_->CreateElement("rglimiter",    audiobin_);
 
261
    audioconvert2_ = engine_->CreateElement("audioconvert", audiobin_);
 
262
    event_probe = audioconvert2_;
 
263
    convert_sink = rgvolume_;
 
264
 
 
265
    if (!rgvolume_ || !rglimiter_ || !audioconvert2_) {
 
266
      return false;
 
267
    }
184
268
 
185
269
    // Set replaygain settings
186
270
    g_object_set(G_OBJECT(rgvolume_), "album-mode", rg_mode_, NULL);
188
272
    g_object_set(G_OBJECT(rglimiter_), "enabled", int(rg_compression_), NULL);
189
273
  }
190
274
 
191
 
  GstPad* pad = gst_element_get_pad(audioconvert_, "sink");
 
275
  // Create a pad on the outside of the audiobin and connect it to the pad of
 
276
  // the first element.
 
277
  GstPad* pad = gst_element_get_pad(queue_, "sink");
192
278
  gst_element_add_pad(audiobin_, gst_ghost_pad_new("sink", pad));
193
279
  gst_object_unref(pad);
194
280
 
195
281
  // Add a data probe on the src pad of the audioconvert element for our scope.
196
282
  // We do it here because we want pre-equalized and pre-volume samples
197
 
  // so that our visualization are not affected by them
198
 
  pad = gst_element_get_pad(scope_element, "src");
199
 
  gst_pad_add_buffer_probe(pad, G_CALLBACK(HandoffCallback), this);
 
283
  // so that our visualization are not be affected by them.
 
284
  pad = gst_element_get_pad(event_probe, "src");
200
285
  gst_pad_add_event_probe(pad, G_CALLBACK(EventHandoffCallback), this);
201
 
  gst_object_unref (pad);
 
286
  gst_object_unref(pad);
202
287
 
 
288
  // Configure the fakesink properly
 
289
  g_object_set(G_OBJECT(probe_sink), "sync", TRUE, NULL);
 
290
  
203
291
  // Set the equalizer bands
204
292
  g_object_set(G_OBJECT(equalizer_), "num-bands", 10, NULL);
205
293
 
217
305
    g_object_unref(G_OBJECT(band));
218
306
  }
219
307
 
220
 
  // Ensure we get the right type out of audioconvert for our scope
221
 
  GstCaps* caps = gst_caps_new_simple ("audio/x-raw-int",
 
308
  // Set the buffer duration.  We set this on the queue as well as on the
 
309
  // decode bin (in ReplaceDecodeBin()) because setting it on the decode bin
 
310
  // only affects network sources.
 
311
  g_object_set(G_OBJECT(queue_), "max-size-time", buffer_duration_nanosec_, NULL);
 
312
 
 
313
  gst_element_link(queue_, audioconvert_);
 
314
  
 
315
  // Create the caps to put in each path in the tee.  The scope path gets 16-bit
 
316
  // ints and the audiosink path gets float32.
 
317
  GstCaps* caps16 = gst_caps_new_simple ("audio/x-raw-int",
222
318
      "width", G_TYPE_INT, 16,
223
319
      "signed", G_TYPE_BOOLEAN, true,
224
320
      NULL);
225
 
  gst_element_link_filtered(scope_element, equalizer_preamp_, caps);
226
 
  gst_caps_unref(caps);
227
 
 
228
 
  // Add an extra audioconvert at the end as osxaudiosink supports only one format.
229
 
  GstElement* convert = engine_->CreateElement("audioconvert", audiobin_);
230
 
  if (!convert) { return false; }
231
 
  if (rg_enabled_)
232
 
    gst_element_link_many(audioconvert_, rgvolume_, rglimiter_, audioconvert2_, NULL);
233
 
  gst_element_link_many(equalizer_preamp_, equalizer_, volume_, audioscale_, convert, audiosink_, NULL);
234
 
 
 
321
  GstCaps* caps32 = gst_caps_new_simple ("audio/x-raw-float",
 
322
      "width", G_TYPE_INT, 32,
 
323
      NULL);
 
324
 
 
325
  // Link the elements with special caps
 
326
  gst_element_link_filtered(probe_converter, probe_sink, caps16);
 
327
  gst_element_link_filtered(audioconvert_, convert_sink, caps32);
 
328
  gst_caps_unref(caps16);
 
329
  gst_caps_unref(caps32);
 
330
 
 
331
  // Link the outputs of tee to the queues on each path.
 
332
  gst_pad_link(gst_element_get_request_pad(tee, "src%d"), gst_element_get_pad(probe_queue, "sink"));
 
333
  gst_pad_link(gst_element_get_request_pad(tee, "src%d"), gst_element_get_pad(audio_queue, "sink"));
 
334
 
 
335
  // Link replaygain elements if enabled.
 
336
  if (rg_enabled_) {
 
337
    gst_element_link_many(rgvolume_, rglimiter_, audioconvert2_, tee, NULL);
 
338
  }
 
339
 
 
340
  // Link everything else.
 
341
  gst_element_link(probe_queue, probe_converter);
 
342
  gst_element_link_many(audio_queue, equalizer_preamp_, equalizer_, volume_,
 
343
                        audioscale_, convert, audiosink_, NULL);
 
344
 
 
345
  // Add probes and handlers.
 
346
  gst_pad_add_buffer_probe(gst_element_get_pad(probe_converter, "src"), G_CALLBACK(HandoffCallback), this);
235
347
  gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this);
236
348
  bus_cb_id_ = gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);
 
349
 
 
350
  MaybeLinkDecodeToAudio();
 
351
 
237
352
  return true;
238
353
}
239
354
 
 
355
void GstEnginePipeline::MaybeLinkDecodeToAudio() {
 
356
  if (!uridecodebin_ || !audiobin_)
 
357
    return;
 
358
 
 
359
  GstPad* pad = gst_element_get_static_pad(uridecodebin_, "src");
 
360
  if (!pad)
 
361
    return;
 
362
 
 
363
  gst_object_unref(pad);
 
364
  gst_element_link(uridecodebin_, audiobin_);
 
365
}
 
366
 
240
367
bool GstEnginePipeline::InitFromString(const QString& pipeline) {
241
368
  pipeline_ = gst_pipeline_new("pipeline");
242
369
 
253
380
 
254
381
bool GstEnginePipeline::InitFromUrl(const QUrl &url, qint64 end_nanosec) {
255
382
  pipeline_ = gst_pipeline_new("pipeline");
256
 
 
257
 
  url_ = url;
 
383
  
 
384
  if (url.scheme() == "cdda" && !url.path().isEmpty()) {
 
385
    // Currently, Gstreamer can't handle input CD devices inside cdda URL. So
 
386
    // we handle them ourselve: we extract the track number and re-create an
 
387
    // URL with only cdda:// + the track number (which can be handled by
 
388
    // Gstreamer). We keep the device in mind, and we will set it later using
 
389
    // SourceSetupCallback
 
390
    QStringList path = url.path().split('/');
 
391
    url_ = QUrl(QString("cdda://%1").arg(path.takeLast()));
 
392
    source_device_ = path.join("/");
 
393
  } else {
 
394
    url_ = url;
 
395
  }
258
396
  end_offset_nanosec_ = end_nanosec;
259
397
 
260
398
  // Decode bin
261
 
  if (!ReplaceDecodeBin(url)) return false;
 
399
  if (!ReplaceDecodeBin(url_)) return false;
262
400
 
263
401
  return Init();
264
402
}
277
415
gboolean GstEnginePipeline::BusCallback(GstBus*, GstMessage* msg, gpointer self) {
278
416
  GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
279
417
 
280
 
  switch ( GST_MESSAGE_TYPE(msg)) {
 
418
  qLog(Debug) << instance->id() << "bus message" << GST_MESSAGE_TYPE_NAME(msg);
 
419
 
 
420
  switch (GST_MESSAGE_TYPE(msg)) {
281
421
    case GST_MESSAGE_ERROR:
282
422
      instance->ErrorMessageReceived(msg);
283
423
      break;
300
440
GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg, gpointer self) {
301
441
  GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
302
442
 
 
443
  qLog(Debug) << instance->id() << "sync bus message" << GST_MESSAGE_TYPE_NAME(msg);
 
444
 
303
445
  switch (GST_MESSAGE_TYPE(msg)) {
304
446
    case GST_MESSAGE_EOS:
305
447
      emit instance->EndOfStreamReached(instance->id(), false);
361
503
    return;
362
504
  }
363
505
 
364
 
  qDebug() << debugstr;
 
506
  qLog(Error) << id() << debugstr;
 
507
 
365
508
  emit Error(id(), message, domain, code);
366
509
}
367
510
 
424
567
  GstPad* const audiopad = gst_element_get_pad(instance->audiobin_, "sink");
425
568
 
426
569
  if (GST_PAD_IS_LINKED(audiopad)) {
427
 
    qDebug() << "audiopad is already linked. Unlinking old pad.";
 
570
    qLog(Warning) << instance->id() << "audiopad is already linked, unlinking old pad";
428
571
    gst_pad_unlink(audiopad, GST_PAD_PEER(audiopad));
429
572
  }
430
573
 
493
636
bool GstEnginePipeline::EventHandoffCallback(GstPad*, GstEvent* e, gpointer self) {
494
637
  GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
495
638
 
 
639
  qLog(Debug) << instance->id() << "event" << GST_EVENT_TYPE_NAME(e);
 
640
 
496
641
  if (GST_EVENT_TYPE(e) == GST_EVENT_NEWSEGMENT && !instance->segment_start_received_) {
497
642
    // The segment start time is used to calculate the proper offset of data
498
643
    // buffers from the start of the stream
500
645
    gst_event_parse_new_segment(e, NULL, NULL, NULL, &start, NULL, NULL);
501
646
    instance->segment_start_ = start;
502
647
    instance->segment_start_received_ = true;
 
648
 
 
649
    if (instance->emit_track_ended_on_segment_start_) {
 
650
      instance->emit_track_ended_on_segment_start_ = false;
 
651
      emit instance->EndOfStreamReached(instance->id(), true);
 
652
    }
503
653
  }
504
654
 
505
655
  return true;
513
663
  }
514
664
}
515
665
 
 
666
void GstEnginePipeline::SourceSetupCallback(GstURIDecodeBin* bin, GParamSpec *pspec, gpointer self) {
 
667
  GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
 
668
  GstElement* element;
 
669
  g_object_get(bin, "source", &element, NULL);
 
670
  if (element &&
 
671
      g_object_class_find_property(G_OBJECT_GET_CLASS(element), "device") &&
 
672
      !instance->source_device().isEmpty()) {
 
673
    // Gstreamer is not able to handle device in URL (refering to Gstreamer
 
674
    // documentation, this might be added in the future). Despite that, for now
 
675
    // we include device inside URL: we decompose it during Init and set device
 
676
    // here, when this callback is called.
 
677
    g_object_set(element, "device", instance->source_device().toLocal8Bit().constData(), NULL);
 
678
  }
 
679
  if (element &&
 
680
      g_object_class_find_property(G_OBJECT_GET_CLASS(element), "extra-headers") &&
 
681
      instance->url().host().contains("grooveshark")) {
 
682
    // Grooveshark streaming servers will answer with a 400 error 'Bad request'
 
683
    // if we don't specify 'Range' field in HTTP header.
 
684
    // Maybe it could be usefull in some other cases, but for now, I prefer to
 
685
    // keep this grooveshark specific.
 
686
    GstStructure* headers;
 
687
    headers = gst_structure_new("extra-headers", "Range", G_TYPE_STRING, "bytes=0-", NULL);
 
688
    g_object_set(element, "extra-headers", headers, NULL);
 
689
    gst_structure_free(headers);
 
690
  }
 
691
}
 
692
 
516
693
void GstEnginePipeline::TransitionToNext() {
517
694
  GstElement* old_decode_bin = uridecodebin_;
518
695
 
520
697
 
521
698
  ReplaceDecodeBin(next_url_);
522
699
  gst_element_set_state(uridecodebin_, GST_STATE_PLAYING);
 
700
  MaybeLinkDecodeToAudio();
523
701
 
524
702
  url_ = next_url_;
525
703
  end_offset_nanosec_ = next_end_offset_nanosec_;
527
705
  next_beginning_offset_nanosec_ = 0;
528
706
  next_end_offset_nanosec_ = 0;
529
707
 
530
 
  // This just tells the UI that we've moved on to the next song
531
 
  emit EndOfStreamReached(id(), true);
 
708
  // This function gets called when the source has been drained, even if the
 
709
  // song hasn't finished playing yet.  We'll get a new segment when it really
 
710
  // does finish, so emit TrackEnded then.
 
711
  emit_track_ended_on_segment_start_ = true;
532
712
 
533
713
  // This has to happen *after* the gst_element_set_state on the new bin to
534
714
  // fix an occasional race condition deadlock.