0

the general goal is that i want to play an audio track on my RPi with aplay ("aplay example.mp3") and the output audio gets looped back into an gstreamer program. This program then does a spectrum analysis.

I got the spectrum analysis already working on a static file with this code as source:

data.source = gst_element_factory_make ("uridecodebin", "source");  
g_object_set (data.source, "uri", "file:///home/pi/example.mp3", NULL);  

ofc i want to use the overall output from my RPi as a source for the program but i dont know how. I know i need to loopback the audio from the output to the input and i found that snd-aloop looks promising. Problem is i still dont know how to use it. I tried to do:

data.source = gst_element_factory_make ("alsasrc", "source");
g_object_set(data.source, "device", XXX ,NULL);

where XXX =

  1. "alsa_output.platform-snd_aloop.0.analog-stereo.monitor"
  2. "hw:1"
  3. "hw:0"

Error -> Trying to dispose element sink, but it is in READY instead of the NULL state. You need to explicitly set Elements to the NULL state before dropping the final reference [...]

Bonus question: Is it possible to pipe audio into a gstreamer program? something like: "aplay example.mp3 > gstreamerCprogram".

Here is the code:

#include <gst/gst.h>

#define AUDIOFREQ 32000

/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
  GstElement *pipeline;
  GstElement *source;
  GstElement *convert;
  GstElement *sink;
} CustomData;

/* Handler for the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *pad, CustomData *data);

static gboolean message_handler (GstBus *bus, GstMessage *message, gpointer data){

    if(message->type == GST_MESSAGE_EOS){
        g_printerr("EOS\n");
    }
    if(message->type == GST_MESSAGE_ELEMENT){
        const GstStructure *s = gst_message_get_structure (message);
        const gchar *name = gst_structure_get_name(s);

        if(strcmp(name, "spectrum") == 0){
            const GValue *magnitudes;
            gdouble freq;

            magnitudes = gst_structure_get_value (s,"magnitude");
            int i = 0;            
            for(i = 0; i < 20; ++i){
                freq = (gdouble)((32000/2) * i + 32000 / 4 / 20);
                if(freq > 10000){
                g_printerr("%f\n",freq);
                }else{
                    g_printerr("|");
                }
            }

        }


        }

}

int main(int argc, char *argv[]) {
  CustomData data;
  GstCaps *caps;
  GstElement *spectrum;
  GstBus *bus;
  GstMessage *msg;
  GstStateChangeReturn ret;
  gboolean terminate = FALSE;

  /* Initialize GStreamer */
  gst_init (&argc, &argv);

  //____________________________HERE IS THE PROBLEM________________________
  //data.source = gst_element_factory_make ("uridecodebin", "source");
  //g_object_set (data.source, "uri", "file:///home/pi/example.mp3", NULL);

  data.source = gst_element_factory_make ("alsasrc", "source");
  g_object_set(data.source, "device", "alsa_output.platform-snd_aloop.0.analog-stereo.monitor",NULL);

  //____________________________HERE ENDS THE PROBLEM________________________

  data.convert = gst_element_factory_make ("audioconvert", "convert");
  data.sink = gst_element_factory_make ("autoaudiosink", "sink");
  spectrum = gst_element_factory_make ("spectrum", "spectrum");
  caps = gst_caps_new_simple ("audio/x-raw", "rate",G_TYPE_INT, AUDIOFREQ, NULL);

  //SET SOME VARIABLES ON SPECTRUM
  g_object_set (G_OBJECT (spectrum), "bands", 20, "post-messages", TRUE, "message-phase", TRUE, NULL);   

  /* Create the empty pipeline */
  data.pipeline = gst_pipeline_new ("test-pipeline");

  if (!data.pipeline || !data.source || !data.convert || !data.sink || !caps || !spectrum) {
    g_printerr ("Not all elements could be created.\n");
    return -1;
  }

  /* Build the pipeline. Note that we are NOT linking the source at this
   * point. We will do it later. */
  gst_bin_add_many (GST_BIN (data.pipeline), data.source, data.convert , spectrum,data.sink, NULL);
  if (!gst_element_link_many (data.convert, spectrum, data.sink, NULL)) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (data.pipeline);
    return -1;
  }

  /* Connect to the pad-added signal */
  g_signal_connect (data.source, "pad-added", G_CALLBACK (pad_added_handler), &data);

  /* Start playing */
  ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (data.pipeline);
    return -1;
  }

  GMainLoop *loop;

  /* Listen to the bus */
  bus = gst_element_get_bus (data.pipeline);
  gst_bus_add_watch(bus, message_handler, NULL);
  loop = g_main_loop_new (NULL,FALSE);
  g_main_loop_run(loop); 

  /* Free resources */
  gst_object_unref (bus);
  gst_element_set_state (data.pipeline, GST_STATE_NULL);
  gst_object_unref (data.pipeline);
  return 0;
}

/* This function will be called by the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *new_pad, CustomData *data) {
  GstPad *sink_pad = gst_element_get_static_pad (data->convert, "sink");
  GstPadLinkReturn ret;
  GstCaps *new_pad_caps = NULL;
  GstStructure *new_pad_struct = NULL;
  const gchar *new_pad_type = NULL;

  g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad), GST_ELEMENT_NAME (src));

  /* If our converter is already linked, we have nothing to do here */
  if (gst_pad_is_linked (sink_pad)) {
    g_print ("  We are already linked. Ignoring.\n");
    goto exit;
  }

  /* Check the new pad's type */
  new_pad_caps = gst_pad_query_caps (new_pad, NULL);
  new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
  new_pad_type = gst_structure_get_name (new_pad_struct);
  if (!g_str_has_prefix (new_pad_type, "audio/x-raw")) {
    g_print ("  It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);
    goto exit;
  }

  /* Attempt the link */
  ret = gst_pad_link (new_pad, sink_pad);
  if (GST_PAD_LINK_FAILED (ret)) {
    g_print ("  Type is '%s' but link failed.\n", new_pad_type);
  } else {
    g_print ("  Link succeeded (type '%s').\n", new_pad_type);
  }

exit:
  /* Unreference the new pad's caps, if we got them */
  if (new_pad_caps != NULL)
    gst_caps_unref (new_pad_caps);

  /* Unreference the sink pad */
  gst_object_unref (sink_pad);
}
Loading
  • 1,098
  • 1
  • 12
  • 25
  • "Bonus question" - Do we get a teddy bear if we can answer this? - Seriously: we are not a debugging service. Read [ask] and provide a [mcve]. – too honest for this site Jun 12 '17 at 14:08
  • You already posted the same thing under my last question and provided zero input, ofc i read the how to ask post.. Could you tell me what i did this time wrong? I mean i can repost this all day long if you dont tell me what iam doing wrong... I posted the whole code, marked the important parts of the code, provided my different solutions (just so you know i spend some time trying to find my own solution) and told you the error code. I also explained what the code should accomplish. – Loading Jun 12 '17 at 14:46
  • If you read the linked pages, why don't you follow the advice? – too honest for this site Jun 12 '17 at 14:49
  • if you could point me to the parts iam doing wrong, this would be a great help, as iam obviously missing these points – Loading Jun 12 '17 at 14:59
  • Use `gst-launch-1.0` command to test a pipeline that just saves the sound into a file. That way you'll debug the loopback setup separately without bothering about the C code. – Velkan Jun 13 '17 at 08:56

0 Answers0