#include <gst/gst.h>

#include <string.h>

#include "gstappsrc.h"
#include "gstappbuffer.h"

const gchar *audio_caps = "audio/x-raw-int,channels=1,rate=8000,signed=(boolean)true,width=16,depth=16";

struct programData {

  GMainLoop *loop;
  GstElement *source;
  GstElement *sink;
};

static gboolean
on_eos (gpointer data)
{
  g_main_loop_quit (((struct programData *)data)->loop);
}

static void
on_handoff_from_source (GstElement *elt,
			GstBuffer *buffer,
			GstPad *pad,
			gpointer data)
{
  guint size;
  gpointer raw_buffer;
  GstBuffer *app_buffer;
  GstElement *source;

  size = GST_BUFFER_SIZE (buffer);
  g_print ("Pushing a buffer of size %d\n", size);
  raw_buffer = g_malloc0 (size);
  memcpy (raw_buffer, GST_BUFFER_DATA (buffer), size);
  app_buffer = gst_app_buffer_new (raw_buffer, size, g_free, raw_buffer);

  gst_buffer_set_caps (app_buffer, GST_BUFFER_CAPS (buffer));
  source = gst_bin_get_by_name (GST_BIN (((struct programData *)data)->sink),
				"testsource");
  gst_app_src_push_buffer (GST_APP_SRC (source), app_buffer);
}

static gboolean
on_source_message (GstBus *bus,
		   GstMessage *message,
		   gpointer data)
{
  if (message->type & GST_MESSAGE_EOS) {

    g_print ("The source got dry\n");
    g_timeout_add (2000, on_eos, data); /* to have time to hear the output */
  }

  return TRUE;
}

static gboolean
on_sink_message (GstBus *bus,
		 GstMessage *message,
		 gpointer data)
{
  /* nil */
  return TRUE;
}

int
main (int argc,
      char *argv[])
{
  gchar *filename = NULL;
  struct programData *data = NULL;
  gchar *string = NULL;
  GstBus *bus = NULL;
  GstElement *testsink = NULL;
  GstElement *testsource = NULL;

  gst_init (&argc, &argv);

  if (argc == 2)
    filename = g_strdup (argv[1]);
  else
    filename = g_strdup ("/usr/share/sounds/ekiga-snapshot/ring.wav");

  data = g_new0 (struct programData, 1);

  data->loop = g_main_loop_new (NULL, FALSE);

  /* setting up source pipeline */
  string = g_strdup_printf ("filesrc location=%s ! wavparse ! %s ! fakesink name=testsink", filename, audio_caps);
  g_free (filename);
  data->source = gst_parse_launch (string, NULL);
  g_free (string);

  if (data->source == NULL)
    g_print ("Bad source\n");

  bus = gst_element_get_bus (data->source);
  gst_bus_add_watch (bus, on_source_message, data);
  gst_object_unref (bus);

  testsink = gst_bin_get_by_name (GST_BIN (data->source), "testsink");
  g_object_set (G_OBJECT (testsink),
		"signal-handoffs", TRUE,
		"sync", FALSE,
		NULL);
  g_signal_connect (testsink, "handoff",
		    G_CALLBACK (on_handoff_from_source), data);
  gst_object_unref (testsink);

  /* setting up sink pipeline */
  string = g_strdup_printf ("appsrc name=testsource ! %s ! autoaudiosink",
			    audio_caps);
  data->sink = gst_parse_launch (string, NULL);
  g_free (string);

  if (data->sink == NULL)
    g_print ("Bad sink\n");

  testsource = gst_bin_get_by_name (GST_BIN (data->sink), "testsource");
  gst_base_src_set_format (GST_BASE_SRC (testsource), GST_FORMAT_TIME);
  gst_object_unref (testsource);

  bus = gst_element_get_bus (data->sink);
  gst_bus_add_watch (bus, on_sink_message, data);
  gst_object_unref (bus);

  /* launching things */
  gst_element_set_state (data->sink, GST_STATE_PLAYING);
  gst_element_set_state (data->source, GST_STATE_PLAYING);

  /* let's run ! */
  g_print ("Let's run!\n");
  g_main_loop_run (data->loop);
  g_print ("Going out\n");

  gst_element_set_state (data->source, GST_STATE_NULL);
  gst_element_set_state (data->sink, GST_STATE_NULL);

  gst_object_unref (data->source);
  gst_object_unref (data->sink);
  g_main_loop_unref (data->loop);
  g_free (data);

  return 0;
}
