#include <gst/gst.h>
#include <gio/gio.h>

static GMainLoop *loop;
static GstElement *pipeline;

static gboolean
message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
{
  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR:{
      GError *err = NULL;
      gchar *name, *debug = NULL;

      name = gst_object_get_path_string (message->src);
      gst_message_parse_error (message, &err, &debug);

      g_printerr ("ERROR: from element %s: %s\n", name, err->message);
      if (debug != NULL)
        g_printerr ("Additional debug info:\n%s\n", debug);

      g_error_free (err);
      g_free (debug);
      g_free (name);

      g_main_loop_quit (loop);
      break;
    }
    case GST_MESSAGE_WARNING:{
      GError *err = NULL;
      gchar *name, *debug = NULL;

      name = gst_object_get_path_string (message->src);
      gst_message_parse_warning (message, &err, &debug);

      g_printerr ("ERROR: from element %s: %s\n", name, err->message);
      if (debug != NULL)
        g_printerr ("Additional debug info:\n%s\n", debug);

      g_error_free (err);
      g_free (debug);
      g_free (name);
      break;
    }
    case GST_MESSAGE_EOS:
      g_print ("Got EOS\n");
      g_main_loop_quit (loop);
      break;
    default:
      break;
  }

  return TRUE;
}

int
main (int argc, char **argv)
{
  GstBus *bus;

  gst_init (&argc, &argv);

  pipeline =
      gst_parse_launch ("autoaudiosrc ! capsfilter caps=audio/x-raw,rate=44100 ! audioconvert ! audioresample ! \
        queue ! mulawenc ! rtppcmupay ! udpsink name=udp-sink \
        udpsrc name=udp-src caps=\"application/x-rtp,media=audio,clock-rate=8000,encoding-name=PCMU\" ! rtppcmudepay ! mulawdec ! \
        audioconvert ! audioresample ! autoaudiosink",
      NULL);

  if (!pipeline) {
    g_error ("Failed to create elements");
    return -1;
  }

  GSocket *gsocket = NULL;
  GSocketAddress *rtp_sockaddr = NULL;
  GInetAddress *inetaddr = NULL;
  gsocket =
      g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
      G_SOCKET_PROTOCOL_UDP, NULL);
  inetaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
  rtp_sockaddr = g_inet_socket_address_new (inetaddr, 16384);
  g_socket_bind (gsocket, rtp_sockaddr, FALSE, NULL);

  GstElement *udp = gst_bin_get_by_name (GST_BIN (pipeline), "udp-sink");
  g_object_set (G_OBJECT (udp), "async", FALSE, "socket", gsocket,      // problematic
      NULL);

  loop = g_main_loop_new (NULL, FALSE);

  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  gst_bus_add_signal_watch (bus);
  g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (message_cb), NULL);
  gst_object_unref (GST_OBJECT (bus));

  if (gst_element_set_state (pipeline,
          GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
    g_error ("Failed to go into PLAYING state");
    return -3;
  }

  g_main_loop_run (loop);

  gst_element_set_state (pipeline, GST_STATE_NULL);

  g_main_loop_unref (loop);
  gst_object_unref (pipeline);

  return 0;
}
