#define _POSIX_C_SOURCE 199309 

#include <time.h>
#include <stdlib.h>
#include <gst/gst.h>

#define POLL_INTERVAL (GST_MSECOND)
#define AUDIOSINK "sunaudiosink"

void do_sleep (GstClockTime next)
{
  GTimeVal time;
  GstClockTime cur;
  struct timespec sleep_time;

  g_get_current_time (&time);
  cur = time.tv_sec * GST_SECOND + time.tv_usec * GST_USECOND;

  /* sleep for next - cur ns */
  if (next > cur) {
    sleep_time.tv_sec = (next - cur) / GST_SECOND;
    sleep_time.tv_nsec = (next - cur) % GST_SECOND;

    while (nanosleep (&sleep_time, &sleep_time) == EINTR); 
  }
}

int
main (int argc, char *argv[])
{
  GstElement *bin, *src, *audiosink;
  GstElement *conv;
  GstClock *clock;
  GTimeVal time;
  GstClockTime start, cur, next, pipe_time, int_time;

  if (!g_thread_supported ())
    g_thread_init (NULL);

  gst_init (&argc, &argv);

  /* create a new bin to hold the elements */
  bin = gst_pipeline_new ("pipeline");
  g_assert (bin);

  src = gst_element_factory_make ("audiotestsrc", NULL);
  g_object_set (src, "wave", 4, NULL);

  conv = gst_element_factory_make ("audioconvert", "audioconvert");
  if (!conv) {
    g_print ("could not create \"audioconvert\" element!");
    return -1;
  }

  /* and an audio sink */
  audiosink = gst_element_factory_make (AUDIOSINK, NULL);
  if (!audiosink) {
    g_print ("could not create audiosink: " AUDIOSINK "\n");
    return -1;
  }

  // g_object_set (audiosink, "latency-time", (gint64) 5000, NULL);
  g_object_set (audiosink, "buffer-time", (gint64) 30000, NULL);

  // g_object_set (audiosink, "device", "hw:0,0", NULL);

  /* add objects to the main pipeline */
  gst_bin_add_many (GST_BIN (bin), src, conv, audiosink, NULL);

  /* link the elements */
  gst_element_link_many (src, conv, audiosink, NULL);

  /* start playing */
  if (gst_element_set_state (bin, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
    g_print ("Could not set pipeline playing\n");
    return -1;
  }
  if (gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE) ==
      GST_STATE_CHANGE_FAILURE) {
    g_print ("Could not set pipeline playing\n");
    return -1;
  }

  clock = gst_element_get_clock (bin);
  if (!clock) {
    g_print ("Pipeline has no clock!\n");
    return -1;
  }

  g_get_current_time (&time);
  next = start = time.tv_sec * GST_SECOND + time.tv_usec * GST_USECOND;

  g_print ("system_time clock clock_internal\n");

  pipe_time = 0;

  while (TRUE) {
    /* Measure the current system time */
    g_get_current_time (&time);
    cur = time.tv_sec * GST_SECOND + time.tv_usec * GST_USECOND;

    int_time = gst_clock_get_internal_time (clock);
    if (pipe_time < int_time)
      pipe_time = int_time;

    /* Print cur time, clock time and internal clock time */
    g_print ("%lld %lld %lld\n", cur - start, pipe_time, int_time);

    do_sleep (next);
    /* 1 mS between readings */
    next += POLL_INTERVAL;
  }

  exit (0);
}
