0

I have a basic gstreamer command for playing audio stream received from network:

gst-launch-1.0 tcpserversrc host=127.0.0.1 port=5000 ! decodebin ! audioconvert ! alsasink

I tried to convert it to a C program, but when I'm running it I get "Internal data flow error".

#include <gst/gst.h>


static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;

  switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;

    case GST_MESSAGE_ERROR: {
      gchar  *debug;
      GError *error;

      gst_message_parse_error (msg, &error, &debug);
      g_free (debug);

      g_printerr ("Error: %s\n", error->message);
      g_error_free (error);

      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }

  return TRUE;
}


gint main (gint   argc, gchar *argv[])
{
  GMainLoop *loop;
  GstElement *pipeline, *src, *dec, *conv, *sink;
  GstBus *bus;

  /* init GStreamer */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* setup */
  pipeline = gst_pipeline_new ("pipeline");

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  src = gst_element_factory_make ("tcpserversrc", "source");
  g_object_set (G_OBJECT (src), "host", "127.0.0.1",NULL);
  g_object_set (G_OBJECT (src), "port", 5000 ,NULL);


  dec = gst_element_factory_make ("decodebin", "decoder");
  conv = gst_element_factory_make ("audioconvert", "aconv");
  sink = gst_element_factory_make ("alsasink", "sink");

  gst_bin_add_many (GST_BIN (pipeline), src, dec, conv, sink, NULL);

  gst_element_link (src, dec);
  gst_element_link (dec, conv);
  gst_element_link (conv, sink);

  /* run */

  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  g_main_loop_run (loop);

  /* cleanup */
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}

Here is the command which I'm using to test the server:

gst-launch-1.0 filesrc location="file.wav" ! tcpclientsink host=127.0.0.1 port=5000

Thanks.

1 Answer 1

2

Because decodebin's src pad is a dynamic (sometimes) pad. You have to connect decodebin to audioconvert when decodebin got its source pad.

You can see it with gst-inspect-1.0:

$ gst-inspect-1.0 decodebin
  :
  :
Pad Templates:
  SRC template: 'src_%u'
    Availability: Sometimes
    Capabilities:
      ANY
  :
  :

Add a callback function for pad-added to decodebin and link to audioconvert in the callback. A required change is basically this:

--- orig.c  2017-01-18 13:35:50.434605255 +0900
+++ new.c   2017-01-18 14:04:16.428847528 +0900
@@ -31,6 +31,21 @@
   return TRUE;
 }

+static void cb_new_pad (GstElement *element, GstPad *pad, gpointer data)
+{
+  gchar *name;
+  GstElement *other = data;
+
+  name = gst_pad_get_name (pad);
+  g_print ("A new pad %s was created for %s\n", name, gst_element_get_name(element));
+  g_free (name);
+
+  g_print ("element %s will be linked to %s\n",
+           gst_element_get_name(element),
+           gst_element_get_name(other));
+  gst_element_link(element, other);
+}
+
 gint main (gint   argc, gchar *argv[])
 {
   GMainLoop *loop;
@@ -59,9 +74,13 @@
   gst_bin_add_many (GST_BIN (pipeline), src, dec, conv, sink, NULL);

   gst_element_link (src, dec);
-  gst_element_link (dec, conv);
   gst_element_link (conv, sink);

+  /* you don't link them here */
+  /* gst_element_link (dec, conv); */
+  /* add call-back, instead */
+  g_signal_connect (dec, "pad-added", G_CALLBACK (cb_new_pad), conv);
+
   /* run */
   gst_element_set_state (pipeline, GST_STATE_PLAYING);
   g_main_loop_run (loop);

Here is a link to a working code.

BTW, you don't have to do it by yourself but let gst_parse_launch() handle all of the above.

int main(int argc, char *argv[])
{
    GstElement *pipeline;
    GError *err = NULL;
    GstBus *bus;
    GMainLoop *loop;

    gst_init(&argc, &argv);

    loop = g_main_loop_new(NULL, FALSE);
    pipeline = gst_parse_launch("tcpserversrc host=127.0.0.1 port=5000 ! decodebin ! audioconvert ! alsasink", &err);
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    bus = gst_element_get_bus(pipeline);
    gst_bus_add_watch (bus, bus_call, loop);
    g_main_loop_run(loop);

    return 0;
}

There are some questions about dynamic pads on stackoverflow:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.