summaryrefslogtreecommitdiff
path: root/src/sydra.c
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2014-09-03 23:09:49 +0200
committerChristian Pointner <equinox@spreadspace.org>2014-09-03 23:09:49 +0200
commita7c3a5c479812f1f69acac276402fdffc60371aa (patch)
tree39bb07552103848862935d8e5c5df20f7135c3f0 /src/sydra.c
added initial code - based on rharchive
Diffstat (limited to 'src/sydra.c')
-rw-r--r--src/sydra.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/sydra.c b/src/sydra.c
new file mode 100644
index 0000000..bded404
--- /dev/null
+++ b/src/sydra.c
@@ -0,0 +1,255 @@
+/*
+ * sydra
+ *
+ * sydra is a toolbox which allows you to set up multiple bidirectional
+ * Video/Audio streams from external locations.
+ * sydra has been written to be used for the Elevate Festival in Graz
+ * Austria in order to involve external locations to present themselves
+ * at the festival.
+ * Sydra is based on GStreamer and is written in C.
+ *
+ *
+ * Copyright (C) 2014 Christian Pointner <equinox@helsinki.at>
+ *
+ * This file is part of sydra.
+ *
+ * sydra is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * sydra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with sydra. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+
+#include <gst/gst.h>
+
+#include "datatypes.h"
+#include "options.h"
+#include "string_list.h"
+#include "log.h"
+#include "sig_handler.h"
+#include "daemon.h"
+#include "writer.h"
+
+static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
+{
+ GMainLoop *loop = (GMainLoop *)data;
+
+ switch (GST_MESSAGE_TYPE(msg)) {
+ case GST_MESSAGE_EOS: {
+ log_printf(NOTICE, "End of stream");
+ g_main_loop_quit(loop);
+ break;
+ }
+ case GST_MESSAGE_INFO: {
+ GError *info;
+ gst_message_parse_info(msg, &info, NULL);
+ log_printf(INFO, "%s", info->message);
+ g_error_free(info);
+ break;
+ }
+ case GST_MESSAGE_WARNING: {
+ GError *warning;
+ gst_message_parse_warning(msg, &warning, NULL);
+ log_printf(WARNING, "%s", warning->message);
+ g_error_free(warning);
+ break;
+ }
+ case GST_MESSAGE_ERROR: {
+ GError *error;
+ gst_message_parse_error(msg, &error, NULL);
+ log_printf(ERROR, "%s", error->message);
+ g_error_free(error);
+ g_main_loop_quit(loop);
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+int main_loop(options_t* opt)
+{
+ log_printf(INFO, "entering main loop");
+
+ GMainLoop *loop;
+ GstElement *pipeline, *source;
+ GstBus *bus;
+ writer_t writer;
+
+ loop = g_main_loop_new(NULL, FALSE);
+ pipeline = gst_pipeline_new("sydra");
+ if(!pipeline || !loop) {
+ log_printf(ERROR, "the pipeline/loop object could not be created. Exiting.");
+ return -1;
+ }
+
+ int ret = writer_init(&writer, loop, opt->name_format_, opt->mode_, opt->nocache_, opt->output_dir_, opt->interval_, opt->offset_, opt->post_process_);
+ if(ret) {
+ gst_object_unref(GST_OBJECT(pipeline));
+ gst_object_unref(GST_OBJECT(loop));
+ return ret;
+ }
+
+ GError *error = NULL;
+ source = gst_parse_bin_from_description(opt->src_bin_desc_, TRUE, &error);
+ if(!source || error) {
+ log_printf(ERROR, "Source Bin Description Parser Error: %s", error ? error->message : "unknown");
+ g_error_free(error);
+ gst_object_unref(GST_OBJECT(writer.sink_));
+ gst_object_unref(GST_OBJECT(pipeline));
+ gst_object_unref(GST_OBJECT(loop));
+ return -1;
+ }
+
+ gst_bin_add_many(GST_BIN(pipeline), source, writer.sink_, NULL);
+ gst_element_link_many(source, writer.sink_, NULL);
+ bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
+ gst_bus_add_watch(bus, bus_call, loop);
+ gst_object_unref(bus);
+
+ log_printf(INFO, "Set State: Paused");
+ gst_element_set_state(pipeline, GST_STATE_PAUSED);
+ log_printf(INFO, "Set State: Playing");
+ gst_element_set_state(pipeline, GST_STATE_PLAYING);
+
+ signal_start(loop);
+ ret = writer_start(&writer);
+ if(!ret) {
+ g_main_loop_run(loop);
+ signal_stop();
+ }
+
+ log_printf(NOTICE, "Stopping pipeline");
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ writer_stop(&writer);
+ gst_object_unref(GST_OBJECT(pipeline));
+
+ return ret;
+}
+
+int main(int argc, char* argv[])
+{
+ log_init();
+
+ options_t opt;
+ int ret = options_parse(&opt, argc, argv);
+ if(ret) {
+ if(ret > 0)
+ fprintf(stderr, "syntax error near: %s\n\n", argv[ret]);
+ if(ret == -2)
+ fprintf(stderr, "memory error on options_parse, exitting\n");
+ if(ret == -3)
+ options_print_version();
+ if(ret == -4)
+ fprintf(stderr, "the interval must be bigger than 0\n");
+
+ if(ret != -2 && ret != -3 && ret != -4)
+ options_print_usage();
+
+ if(ret == -1 || ret == -3)
+ ret = 0;
+
+ options_clear(&opt);
+ log_close();
+ exit(ret);
+ }
+ slist_element_t* tmp = opt.log_targets_.first_;
+ while(tmp) {
+ ret = log_add_target(tmp->data_);
+ if(ret) {
+ switch(ret) {
+ case -2: fprintf(stderr, "memory error on log_add_target, exitting\n"); break;
+ case -3: fprintf(stderr, "unknown log target: '%s', exitting\n", (char*)(tmp->data_)); break;
+ case -4: fprintf(stderr, "this log target is only allowed once: '%s', exitting\n", (char*)(tmp->data_)); break;
+ default: fprintf(stderr, "syntax error near: '%s', exitting\n", (char*)(tmp->data_)); break;
+ }
+
+ options_clear(&opt);
+ log_close();
+ exit(ret);
+ }
+ tmp = tmp->next_;
+ }
+
+ log_printf(NOTICE, "just started...");
+ options_parse_post(&opt);
+
+ priv_info_t priv;
+ if(opt.username_)
+ if(priv_init(&priv, opt.username_, opt.groupname_)) {
+ options_clear(&opt);
+ log_close();
+ exit(-1);
+ }
+
+ FILE* pid_file = NULL;
+ if(opt.pid_file_) {
+ pid_file = fopen(opt.pid_file_, "w");
+ if(!pid_file) {
+ log_printf(WARNING, "unable to open pid file: %s", strerror(errno));
+ }
+ }
+
+ if(opt.chroot_dir_)
+ if(do_chroot(opt.chroot_dir_)) {
+ options_clear(&opt);
+ log_close();
+ exit(-1);
+ }
+ if(opt.username_)
+ if(priv_drop(&priv)) {
+ options_clear(&opt);
+ log_close();
+ exit(-1);
+ }
+
+ if(opt.daemonize_) {
+ pid_t oldpid = getpid();
+ daemonize();
+ log_printf(INFO, "running in background now (old pid: %d)", oldpid);
+ }
+
+ if(pid_file) {
+ pid_t pid = getpid();
+ fprintf(pid_file, "%d", pid);
+ fclose(pid_file);
+ }
+
+ signal_init();
+ gst_init(NULL, NULL);
+ const gchar *nano_str;
+ guint major, minor, micro, nano;
+ gst_version(&major, &minor, &micro, &nano);
+ if (nano == 1)
+ nano_str = " (CVS)";
+ else if (nano == 2)
+ nano_str = " (Prerelease)";
+ else
+ nano_str = "";
+ log_printf(NOTICE, "sydra linked against GStreamer %d.%d.%d%s", major, minor, micro, nano_str);
+
+ ret = main_loop(&opt);
+
+ options_clear(&opt);
+
+ log_printf(NOTICE, "sydra shutdown");
+
+ gst_deinit();
+ log_close();
+
+ return ret;
+}