#include <gst/gst.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstdirectcontrolbinding.h>

struct AppData
{
  GstElement *pipeline;
  GstElement *volume;
  GstControlSource *volume_control;
  GMainLoop *loop;
  gboolean prerolled;
};

static void
error_cb (GstBus * bus, GstMessage * message, struct AppData *data)
{
  g_message ("Error.");
  g_main_loop_quit (data->loop);
}

static void
eos_cb (GstBus * bus, GstMessage * message, struct AppData *data)
{
  g_message ("End-of-Stream.");
  g_main_loop_quit (data->loop);
}

static void
async_done_cb (GstBus * bus, GstMessage * message, struct AppData *data)
{
  g_message ("Async done.");

  if (!data->prerolled) {
    data->prerolled = TRUE;
    gst_element_seek (data->pipeline, 1.0, GST_FORMAT_TIME,
        GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT,
        GST_SEEK_TYPE_SET, 7 * 60 * GST_SECOND,
        GST_SEEK_TYPE_SET, (7 * 60 + 10) * GST_SECOND);
  }
}

static void
segment_done_cb (GstBus * bus, GstMessage * message, struct AppData *data)
{
  static int once = 1;
  GstTimedValueControlSource *tvcs;

  g_message ("Segment done.");

  /* just loop */
  gst_element_seek (data->pipeline, 1.0, GST_FORMAT_TIME,
      GST_SEEK_FLAG_SEGMENT,
      GST_SEEK_TYPE_SET, 7 * 60 * GST_SECOND,
      GST_SEEK_TYPE_SET, (7 * 60 + 10) * GST_SECOND);

  tvcs = (GstTimedValueControlSource *) data->volume_control;

  if (once) {
    gst_timed_value_control_source_set (tvcs, (7 * 60 + 8) * GST_SECOND, 0.7);
    gst_timed_value_control_source_set (tvcs, (7 * 60 + 10) * GST_SECOND, 0.5);
    gst_timed_value_control_source_set (tvcs, (7 * 60 + 0) * GST_SECOND, 0.5);
    gst_timed_value_control_source_set (tvcs, (7 * 60 + 2) * GST_SECOND, 0.0);
    once = 0;
  } else {
    gst_timed_value_control_source_unset_all (tvcs);
  }
}

gint
main (gint argc, gchar ** argv)
{
  struct AppData data;
  gchar *uri;
  GstElement *playbin;
  GstBus *bus;

  gst_init (&argc, &argv);

  if (argc != 2) {
    g_message ("usage: ./test filename");
    return -1;
  }

  if (g_path_is_absolute (argv[1])) {
    uri = g_strdup_printf ("file://%s", argv[1]);
  } else {
    gchar *pwd = g_get_current_dir ();
    uri = g_strdup_printf ("file://%s/%s", pwd, argv[1]);
    g_free (pwd);
  }

  data.pipeline = gst_pipeline_new (NULL);
  playbin  = gst_element_factory_make ("playbin", NULL);
  data.volume  = gst_element_factory_make ("volume", NULL);

  gst_bin_add (GST_BIN (data.pipeline), playbin);

  g_object_set (playbin, "audio-filter", data.volume, "uri", uri, NULL);
  g_free (uri);

  data.loop = g_main_loop_new (NULL, FALSE);

  bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline));
  gst_bus_add_signal_watch (bus);
  g_signal_connect (bus, "message::error", G_CALLBACK (error_cb), &data);
  g_signal_connect (bus, "message::eos", G_CALLBACK (eos_cb), &data);
  g_signal_connect (bus, "message::async-done", G_CALLBACK (async_done_cb), &data);
  g_signal_connect (bus, "message::segment-done", G_CALLBACK (segment_done_cb), &data);
  gst_object_unref (bus);

  data.volume_control = gst_interpolation_control_source_new ();
  g_object_set (data.volume_control, "mode", GST_INTERPOLATION_MODE_CUBIC, NULL);
  gst_object_add_control_binding (GST_OBJECT_CAST (data.volume),
      gst_direct_control_binding_new (GST_OBJECT_CAST (data.volume), "volume", data.volume_control));


  data.prerolled = FALSE;
  gst_element_set_state (data.pipeline, GST_STATE_PLAYING);

  g_main_loop_run (data.loop);

  g_main_loop_unref (data.loop);
  gst_element_set_state (data.pipeline, GST_STATE_NULL);
  gst_object_unref (data.pipeline);

  return 0;
}
