/*
 * gsttest.c
 *
 * Compile with:
 * libtool --mode=link gcc -g3 -O0 -o gsttest -Wall `pkg-config --cflags --libs gstreamer-0.10` gsttest.c
 *
 * Run with the timeout.sh
 * [run-standalone.sh] timeout.sh
 * for i in `seq 1 1000`; do [run-standalone.sh] ./timeout.sh; done | tee /tmp/log.txt
 */

#include <glib-object.h>
#include <gst/gst.h>
/* #include <gst/interfaces/xoverlay.h> */
#include <signal.h>

static GstElement *pipeline = NULL;
static GMainLoop *loop = NULL;
static guint elapsed = 0;
static gboolean success = FALSE;

static void _set_volume(void)
{
	g_return_if_fail(pipeline != NULL);

	g_debug("setting volume %1.1f", 1.0);
	g_object_set(pipeline, "volume", 1.0, NULL);
}

static void _set_mute(void)
{
	gboolean mute = TRUE;

	g_return_if_fail(pipeline != NULL);

	g_debug("setting mute: %s", mute ? "TRUE" : "FALSE");
	g_object_set(pipeline, "mute", mute, NULL);
}

static gboolean _do_play(gpointer user_data)
{
	g_return_val_if_fail (pipeline != NULL, FALSE);

	_set_volume();
	_set_mute();
	gst_element_set_state(pipeline, GST_STATE_PLAYING);
	g_debug("setting pipeline to PLAYING");

	return FALSE;
}

gboolean _do_exit(gpointer user_data)
{
	g_debug("Test exitting");
        g_main_loop_quit (loop);
        return FALSE;
}

static void _handle_state_changed(GstMessage *msg)
{
	GstState current_state, new_state;

	gst_message_parse_state_changed(msg, &current_state, &new_state, NULL);
	g_debug("pipeline changed state from %s to %s",
		gst_element_state_get_name(current_state),
		gst_element_state_get_name(new_state));

	switch (GST_STATE_TRANSITION(current_state, new_state)) {
	case GST_STATE_CHANGE_READY_TO_PAUSED:
		g_debug("Test changed to PAUSED");
		_do_play(NULL);
		break;
	case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
		g_debug("Test changed to PLAYING");
		success = TRUE;
		g_timeout_add_seconds(1, _do_exit, NULL);
		break;
	case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
		g_debug("Test changed to PAUSED");
		break;
	case GST_STATE_CHANGE_PAUSED_TO_READY:
		g_debug("Test changed to READY");
		break;
	default:
		break;
	}
}

static gboolean _async_bus_handler(GstBus *bus, GstMessage *msg,
				   gpointer user_data)
{
	switch (GST_MESSAGE_TYPE(msg)) {
	case GST_MESSAGE_ERROR:
		{
			gchar *debug;
			GError *err;

			debug = NULL;
			gst_message_parse_error(msg, &err, &debug);
			g_error("gst error: domain = %d, code = %d, "
				"message = '%s', debug = '%s'",
				err->domain, err->code, err->message, debug);
		}
		break;
	case GST_MESSAGE_STATE_CHANGED:
		if ((GstElement *)GST_MESSAGE_SRC(msg) == pipeline)
			_handle_state_changed(msg);
			break;
	default:
		break;
	}
	return TRUE;
}

static gboolean _build_pipeline(gpointer user_data)
{
	const gchar *uri = user_data;
	GstBus *bus;
	GstElement *asink = NULL, *vsink = NULL;

	pipeline = gst_element_factory_make("playbin2",
					    "playbin");

	g_assert(pipeline != NULL);

	asink = gst_element_factory_make("fakesink",
					 "audio-sink");
	vsink = gst_element_factory_make("fakesink",
					 "video-sink");
	g_object_set(pipeline, "audio-sink", asink, NULL);
	g_object_set(pipeline, "video-sink", vsink, NULL);

	g_object_set(G_OBJECT(pipeline), "uri", uri, NULL);

	bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));

	gst_bus_add_watch(bus, _async_bus_handler, NULL);

	g_debug("Pipeline built, setting to PAUSED");
	gst_element_set_state(pipeline, GST_STATE_PAUSED);

	return FALSE;
}

static void
_add_action (guint seconds, GSourceFunc action, gpointer user_data)
{
        elapsed += seconds;

	g_timeout_add(elapsed * 1000, action, user_data);
}

static void _print_failure(gint param) {
	g_debug("FAILURE");
	g_assert_not_reached();
}

int main(int argc, char *argv[])
{
	g_assert(argc > 1);

	g_type_init();
	g_thread_init(NULL);
	gst_init(NULL, NULL);

	signal(SIGUSR2, _print_failure);

	g_debug("INIT");

	_add_action(1, _build_pipeline, argv[1]);

        loop = g_main_loop_new(NULL, FALSE);
	g_main_loop_run(loop);

	g_debug(success ? "Success" : "WRONG EXECUTION");

	return 0;
}
