/* 
 * multiChannel.c
 */

#include <gst/gst.h>
#include <gst/audio/multichannel.h>

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

    switch(GST_MESSAGE_TYPE(msg)) 
    {
        case GST_MESSAGE_EOS:
            g_print("End-of-stream\n");
            *done = TRUE;

            //g_main_loop_quit(loop);
            break;
        case GST_MESSAGE_ERROR: 
            {
                gchar *debug = NULL;
                GError *err = NULL;

                gst_message_parse_error(msg, &err, &debug);

                g_print("Error: %s\n", err->message);
                g_error_free(err);

                if (debug) {
                    g_print("Debug details: %s\n", debug);
                    g_free(debug);
                }

                *done = TRUE;
                //g_main_loop_quit(loop);
                break;
            }
        case GST_MESSAGE_STATE_CHANGED:
            //g_print("state changed \n");
            break;
        default:
            break;
    }

    return TRUE;
}


gint main(int argc, char **argv)
{
    gst_init(&argc, &argv);
    GstStateChangeReturn ret;
    const char *err_str = " could not be found - check your install\n";
    enum {NUM_CHANNELS = 64};
    GstElement *pipeline; 
    GstElement *source;
    GstElement *capsfilter;
    GstElement *capsfilter2;
    GstElement *audioconvert;
    GstElement *audioconvert2;
    GstElement *pay;
    GstElement *depay;
    GstElement *sink;
    gboolean done = FALSE;
    GMainLoop *loop;
    GstBus *bus;

    /* initialization */
    loop = g_main_loop_new(NULL, FALSE);

    /* create elements */
    pipeline = gst_pipeline_new("audioPipeline");
    g_signal_connect(pipeline, "deep_notify",
            G_CALLBACK(gst_object_default_deep_notify), NULL);

    /* watch for messages on the pipeline's bus (note that this will only
     * work like this when a GLib main loop is running) */
    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    gst_bus_add_watch(bus, bus_call, &done);
    gst_object_unref(bus);

    if (!(source = gst_element_factory_make("jackaudiosrc", NULL)))
        g_print("source%s", err_str);
    if (!(capsfilter = gst_element_factory_make("capsfilter", NULL)))
        g_print("capsfilter%s", err_str);
    if (!(capsfilter2 = gst_element_factory_make("capsfilter", NULL)))
        g_print("capsfilter2%s", err_str);
    if (!(audioconvert = gst_element_factory_make("audioconvert", NULL)))
        g_print("audioconvert%s", err_str);
    if (!(pay = gst_element_factory_make("rtpL16pay", NULL)))
        g_print("pay%s", err_str);
    if (!(depay = gst_element_factory_make("rtpL16depay", NULL)))
        g_print("depay%s", err_str);
    if (!(audioconvert2 = gst_element_factory_make("audioconvert", NULL)))
        g_print("audioconvert2%s", err_str);
    if (!(sink = gst_element_factory_make("jackaudiosink", NULL)))
        g_print("sink%s", err_str);
    g_object_set(G_OBJECT(source), "connect", 0, NULL);   // don't connect jack ports
    g_object_set(G_OBJECT(sink), "connect", 0, NULL);   // don't connect jack ports

  GstAudioChannelPosition pos[NUM_CHANNELS] = { 
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE,
    GST_AUDIO_CHANNEL_POSITION_NONE
  };

    GstCaps *caps = gst_caps_new_simple("audio/x-raw-float", "channels", G_TYPE_INT, NUM_CHANNELS, NULL);
    g_assert(caps);
    gst_audio_set_channel_positions(gst_caps_get_structure(caps, 0), pos);
    g_object_set(capsfilter, "caps", caps, NULL);
    g_object_set(capsfilter2, "caps", caps, NULL);
    gst_caps_unref(caps);

    gst_bin_add_many(GST_BIN(pipeline), source, capsfilter, audioconvert, pay, depay, capsfilter2, audioconvert2, sink, NULL);
    gst_element_link_many(source, capsfilter, audioconvert, pay, depay, audioconvert2, capsfilter2, sink, NULL);


    /* run */
    ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);

    if (ret == GST_STATE_CHANGE_FAILURE) 
    {
        g_print ("Failed to start up pipeline!\n");

        /* check if there is an error message with details on the bus */
        GstMessage *msg = gst_bus_poll(bus, GST_MESSAGE_ERROR, 0);
        if (msg) 
        {
            GError *err = NULL;

            gst_message_parse_error(msg, &err, NULL);
            g_print("ERROR: %s\n", err->message);
            g_error_free(err);
            gst_message_unref(msg);
        }
        return -1;
    }

    g_main_loop_run(loop);

    /* clean up */
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);

    return 0;
}

