Beispiel #1
0
void GioLister::Init() {
  monitor_.reset_without_add(g_volume_monitor_get());

  // Get existing volumes
  GList* const volumes = g_volume_monitor_get_volumes(monitor_);
  for (GList* p=volumes; p; p=p->next) {
    GVolume* volume = static_cast<GVolume*>(p->data);

    VolumeAdded(volume);
    g_object_unref(volume);
  }
  g_list_free(volumes);

  // Get existing mounts
  GList* const mounts = g_volume_monitor_get_mounts(monitor_);
  for (GList* p=mounts; p; p=p->next) {
    GMount* mount = static_cast<GMount*>(p->data);

    MountAdded(mount);
    g_object_unref(mount);
  }
  g_list_free(mounts);

  // Connect signals from the monitor
  CHECKED_GCONNECT(monitor_, "volume-added", &VolumeAddedCallback, this);
  CHECKED_GCONNECT(monitor_, "volume-removed", &VolumeRemovedCallback, this);
  CHECKED_GCONNECT(monitor_, "mount-added", &MountAddedCallback, this);
  CHECKED_GCONNECT(monitor_, "mount-changed", &MountChangedCallback, this);
  CHECKED_GCONNECT(monitor_, "mount-removed", &MountRemovedCallback, this);
}
bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
  GstElement* new_bin = nullptr;

#ifdef HAVE_SPOTIFY
  if (url.scheme() == "spotify") {
    new_bin = gst_bin_new("spotify_bin");

    // Create elements
    GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
    if (!src) return false;
    GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
    if (!gdp) return false;

    // Pick a port number
    const int port = Utilities::PickUnusedPort();
    g_object_set(G_OBJECT(src), "host", "127.0.0.1", nullptr);
    g_object_set(G_OBJECT(src), "port", port, nullptr);

    // Link the elements
    gst_element_link(src, gdp);

    // Add a ghost pad
    GstPad* pad = gst_element_get_static_pad(gdp, "src");
    gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
    gst_object_unref(GST_OBJECT(pad));

    // Tell spotify to start sending data to us.
    SpotifyServer* spotify_server =
        InternetModel::Service<SpotifyService>()->server();
    // Need to schedule this in the spotify server's thread
    QMetaObject::invokeMethod(
        spotify_server, "StartPlayback", Qt::QueuedConnection,
        Q_ARG(QString, url.toString()), Q_ARG(quint16, port));
  } else {
#endif
    new_bin = engine_->CreateElement("uridecodebin");
    if (!new_bin) return false;
    g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(),
                 nullptr);
    CHECKED_GCONNECT(G_OBJECT(new_bin), "drained", &SourceDrainedCallback,
                     this);
    CHECKED_GCONNECT(G_OBJECT(new_bin), "pad-added", &NewPadCallback, this);
    CHECKED_GCONNECT(G_OBJECT(new_bin), "notify::source", &SourceSetupCallback,
                     this);
#ifdef HAVE_SPOTIFY
  }
#endif

  return ReplaceDecodeBin(new_bin);
}
bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
    GstElement* new_bin = NULL;

    if (url.scheme() == "spotify") {
#ifdef HAVE_SPOTIFY
        new_bin = gst_bin_new("spotify_bin");

        // Create elements
        GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
        GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
        if (!src || !gdp)
            return false;

        // Pick a port number
        const int port = Utilities::PickUnusedPort();
        g_object_set(G_OBJECT(src), "host", "127.0.0.1", NULL);
        g_object_set(G_OBJECT(src), "port", port, NULL);

        // Link the elements
        gst_element_link(src, gdp);

        // Add a ghost pad
        GstPad* pad = gst_element_get_static_pad(gdp, "src");
        gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
        gst_object_unref(GST_OBJECT(pad));

        // Tell spotify to start sending data to us.
        InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(url.toString(), port);
#else // HAVE_SPOTIFY
        qLog(Error) << "Tried to play a spotify:// url, but spotify support is not compiled in";
        return false;
#endif
    } else {
        new_bin = engine_->CreateElement("uridecodebin");
        g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(), NULL);
        CHECKED_GCONNECT(G_OBJECT(new_bin), "drained", &SourceDrainedCallback, this);
        CHECKED_GCONNECT(G_OBJECT(new_bin), "pad-added", &NewPadCallback, this);
        CHECKED_GCONNECT(G_OBJECT(new_bin), "notify::source", &SourceSetupCallback, this);
    }

    return ReplaceDecodeBin(new_bin);
}
Beispiel #4
0
QString Chromaprinter::CreateFingerprint() {
  Q_ASSERT(QThread::currentThread() != qApp->thread());

  buffer_.open(QIODevice::WriteOnly);

  GMainContext* context = g_main_context_new();
  g_main_context_push_thread_default(context);
  event_loop_ = g_main_loop_new(context, FALSE);

  pipeline_ = gst_pipeline_new("pipeline");
  GstElement* src = CreateElement("filesrc", pipeline_);
  GstElement* decode = CreateElement("decodebin2", pipeline_);
  GstElement* convert = CreateElement("audioconvert", pipeline_);
  GstElement* resample = CreateElement("audioresample", pipeline_);
  GstElement* sink = CreateElement("appsink", pipeline_);

  if (!src || !decode || !convert || !resample || !sink) {
    return QString();
  }

  convert_element_ = convert;

  // Connect the elements
  gst_element_link_many(src, decode, nullptr);
  gst_element_link_many(convert, resample, nullptr);

  // Chromaprint expects mono floats at a sample rate of 11025Hz.
  GstCaps* caps = gst_caps_new_simple(
      "audio/x-raw-int", "width", G_TYPE_INT, 16, "channels", G_TYPE_INT,
      kDecodeChannels, "rate", G_TYPE_INT, kDecodeRate, nullptr);
  gst_element_link_filtered(resample, sink, caps);
  gst_caps_unref(caps);

  GstAppSinkCallbacks callbacks;
  memset(&callbacks, 0, sizeof(callbacks));
  callbacks.new_buffer = NewBufferCallback;
  gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks,
                             this, nullptr);
  g_object_set(G_OBJECT(sink), "sync", FALSE, nullptr);
  g_object_set(G_OBJECT(sink), "emit-signals", TRUE, nullptr);

  // Set the filename
  g_object_set(src, "location", filename_.toUtf8().constData(), nullptr);

  // Connect signals
  CHECKED_GCONNECT(decode, "new-decoded-pad", &NewPadCallback, this);
  gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)),
                           BusCallbackSync, this);
  guint bus_callback_id = gst_bus_add_watch(
      gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this);

  QTime time;
  time.start();

  // Start playing
  gst_element_set_state(pipeline_, GST_STATE_PLAYING);

  g_main_loop_run(event_loop_);
  g_main_loop_unref(event_loop_);
  g_main_context_unref(context);

  int decode_time = time.restart();

  buffer_.close();
  QByteArray data = buffer_.data();

  ChromaprintContext* chromaprint =
      chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
  chromaprint_start(chromaprint, kDecodeRate, kDecodeChannels);
  chromaprint_feed(chromaprint, reinterpret_cast<void*>(data.data()),
                   data.size() / 2);
  chromaprint_finish(chromaprint);

  void* fprint = nullptr;
  int size = 0;
  int ret = chromaprint_get_raw_fingerprint(chromaprint, &fprint, &size);
  QByteArray fingerprint;
  if (ret == 1) {
    void* encoded = nullptr;
    int encoded_size = 0;
    chromaprint_encode_fingerprint(fprint, size, CHROMAPRINT_ALGORITHM_DEFAULT,
                                   &encoded, &encoded_size, 1);

    fingerprint.append(reinterpret_cast<char*>(encoded), encoded_size);

    chromaprint_dealloc(fprint);
    chromaprint_dealloc(encoded);
  }
  chromaprint_free(chromaprint);
  int codegen_time = time.elapsed();

  qLog(Debug) << "Decode time:" << decode_time
              << "Codegen time:" << codegen_time;

  // Cleanup
  callbacks.new_buffer = nullptr;
  gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks,
                             this, nullptr);
  gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)),
                           nullptr, nullptr);
  g_source_remove(bus_callback_id);
  gst_element_set_state(pipeline_, GST_STATE_NULL);
  gst_object_unref(pipeline_);

  return fingerprint;
}