summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2014-09-24 23:40:12 +0200
committerChristian Pointner <equinox@spreadspace.org>2014-09-24 23:40:12 +0200
commitc7fd1b11e03b327d1e8c5cfecdcc2c907b393739 (patch)
tree2afa2e17166c0d2bd59aa27003d179d656a888ff
parentmoved pipeline creation subs to own file (diff)
added udp socket handling to own file
-rw-r--r--src/Makefile1
-rw-r--r--src/pipelines.c1
-rw-r--r--src/sydra.c121
-rw-r--r--src/udp.c158
-rw-r--r--src/udp.h43
5 files changed, 205 insertions, 119 deletions
diff --git a/src/Makefile b/src/Makefile
index ac91c33..eb9f39b 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -45,6 +45,7 @@ C_OBJS := log.o \
string_list.o \
utils.o \
pipelines.o \
+ udp.o \
sydra.o
C_SRCS := $(C_OBJS:%.o=%.c)
diff --git a/src/pipelines.c b/src/pipelines.c
index f2f787c..5c687fb 100644
--- a/src/pipelines.c
+++ b/src/pipelines.c
@@ -43,6 +43,7 @@
#include "log.h"
+
struct media_elements {
const char* name_;
diff --git a/src/sydra.c b/src/sydra.c
index 680836d..44abc38 100644
--- a/src/sydra.c
+++ b/src/sydra.c
@@ -53,6 +53,8 @@
#include "daemon.h"
#include "utils.h"
#include "pipelines.h"
+#include "udp.h"
+
static gboolean sig_handler_terminate(gpointer user_data)
{
@@ -163,125 +165,6 @@ static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
return TRUE;
}
-
-
-
-
-static void udp_add_client(struct sockaddr_storage *addr, socklen_t addrlen, struct udp_sink* sink)
-{
- struct addr_port* client = g_new(struct addr_port, 1);
- if(!client) return;
-
- switch(addr->ss_family)
- {
- case AF_INET: client->type_ = IPv4; client->port_ = ntohs(((struct sockaddr_in*)addr)->sin_port); break;
- case AF_INET6: client->type_ = IPv6; client->port_ = ntohs(((struct sockaddr_in6*)addr)->sin6_port); break;
- default: return;
- }
-
- int errcode = getnameinfo((struct sockaddr *)addr, addrlen, client->addr_, sizeof(client->addr_), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
- if (errcode != 0) {
- log_printf(WARNING, "getnameinfo() error: %s", gai_strerror(errcode));
- return;
- }
- gchar* name = gst_element_get_name(sink->udp_);
- if(!g_list_find_custom(sink->clients_, client, cmp_addr_port)) {
- log_printf(INFO, "adding host %s%c%d to list of receivers for element %s", client->addr_, client->type_ == IPv4 ? ':' : '.', client->port_, name);
- g_signal_emit_by_name(G_OBJECT(sink->udp_), "add", client->addr_, client->port_, NULL);
- sink->clients_ = g_list_append(sink->clients_, client);
- } else {
- log_printf(DEBUG, "not adding host %s%c%d to list of receivers for element %s - already added", client->addr_, client->type_ == IPv4 ? ':' : '.', client->port_, name);
- g_free(client);
- }
- g_free(name);
-}
-
-static void udp_remove_client(struct sockaddr_storage *addr, socklen_t addrlen, struct udp_sink* sink)
-{
- // TODO: implement this!
- gchar* name = gst_element_get_name(sink->udp_);
- log_printf(ERROR, "removing client from %s failed! - removing not yet implemented!", name);
- g_free(name);
-}
-
-#define UDP_PROTO_MAGIC "SYDRA:"
-#define UDP_PROTO_MAGIC_LEN (sizeof(UDP_PROTO_MAGIC)-1)
-#define UDP_PROTO_CMD_ADD_CLIENT "add_client\n"
-#define UDP_PROTO_CMD_ADD_CLIENT_LEN (sizeof(UDP_PROTO_CMD_ADD_CLIENT)-1)
-#define UDP_PROTO_CMD_RM_CLIENT "remove_client\n"
-#define UDP_PROTO_CMD_RM_CLIENT_LEN (sizeof(UDP_PROTO_CMD_RM_CLIENT)-1)
-
-static gboolean on_udp_desc_ready(gint fd, GIOCondition cond, gpointer user_data)
-{
- struct udp_sink* sink = (struct udp_sink*)user_data;
- if(!sink || !(sink->udp_)) {
- log_printf(WARNING, "File descriptor %d is ready for reading - but supplied element is NULL removing callback", fd);
- return FALSE;
- }
-
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(addr);
- u_int8_t buf[2048];
- ssize_t bytes = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addrlen);
- if(bytes < 1) {
- if(errno == EINTR)
- return TRUE;
-
- log_printf(WARNING, "Error while receiving UDP data on fd %d, will remove callback", fd);
- return FALSE;
- }
-
- if(bytes < UDP_PROTO_MAGIC_LEN || memcmp(UDP_PROTO_MAGIC, buf, UDP_PROTO_MAGIC_LEN)) {
- log_printf(DEBUG, "client discovery: ignoring invalid incoming packet");
- return TRUE;
- }
-
- u_int8_t* cmd = &(buf[UDP_PROTO_MAGIC_LEN]);
- if(bytes == (UDP_PROTO_MAGIC_LEN+UDP_PROTO_CMD_ADD_CLIENT_LEN) &&
- !memcmp(UDP_PROTO_CMD_ADD_CLIENT, cmd, UDP_PROTO_CMD_ADD_CLIENT_LEN)) {
- udp_add_client(&addr, addrlen, sink);
- } else if(bytes == (UDP_PROTO_MAGIC_LEN+UDP_PROTO_CMD_RM_CLIENT_LEN) &&
- !memcmp(UDP_PROTO_CMD_RM_CLIENT, cmd, UDP_PROTO_CMD_RM_CLIENT_LEN)) {
- udp_remove_client(&addr, addrlen, sink);
- } else {
- log_printf(DEBUG, "client discovery: ignoring invalid command");
- }
- return TRUE;
-}
-
-static gboolean attach_udp_descriptor(struct udp_sink* sink, const char* name, const char* prop)
-{
- GSocket *sock;
- g_object_get(G_OBJECT(sink->udp_), prop, &sock, NULL);
- int fd = g_socket_get_fd(sock);
-
- guint id = g_unix_fd_add(fd, G_IO_IN, on_udp_desc_ready, sink);
- if(id <= 0) {
- log_printf(ERROR, "Error while adding %s file descriptor (%d) to main loop", name, fd);
- return FALSE;
- }
- log_printf(DEBUG, "successfully installed callback for %s (fd: %d) for reading (id: %d)", name, fd, id);
- return TRUE;
-}
-
-
-static gboolean attach_udp_descriptors(struct udp_sinks *sinks)
-{
- if(!attach_udp_descriptor(&(sinks->rtp_video_), "RTP(video) IPv4", "used-socket") ||
- !attach_udp_descriptor(&(sinks->rtp_video_), "RTP(video) IPv6", "used-socket-v6") ||
- !attach_udp_descriptor(&(sinks->rtcp_video_), "RTCP(video) IPv4", "used-socket") ||
- !attach_udp_descriptor(&(sinks->rtcp_video_), "RTCP(video) IPv6", "used-socket-v6") ||
- !attach_udp_descriptor(&(sinks->rtp_audio_), "RTP(audio) IPv4", "used-socket") ||
- !attach_udp_descriptor(&(sinks->rtp_audio_), "RTP(audio) IPv6", "used-socket-v6") ||
- !attach_udp_descriptor(&(sinks->rtcp_audio_), "RTCP(audio) IPv4", "used-socket") ||
- !attach_udp_descriptor(&(sinks->rtcp_audio_), "RTCP(audio) IPv6", "used-socket-v6")) {
- return FALSE;
- }
- return TRUE;
-}
-
-
-
int main_loop(options_t* opt)
{
log_printf(INFO, "entering main loop");
diff --git a/src/udp.c b/src/udp.c
new file mode 100644
index 0000000..bce74d7
--- /dev/null
+++ b/src/udp.c
@@ -0,0 +1,158 @@
+/*
+ * 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@spreadspace.org>
+ *
+ * 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/>.
+ *
+ * In addition, as a special exception, the copyright holders hereby
+ * grant permission for non-GPL-compatible GStreamer plugins to be used
+ * and distributed together with GStreamer and sydra.
+ * This permission goes above and beyond the permissions granted by the
+ * GPL license sydra is covered by.
+ */
+
+#include "datatypes.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib-unix.h>
+#include <gio/gio.h>
+#include <gst/gst.h>
+
+#include "utils.h"
+#include "log.h"
+
+
+static void udp_add_client(struct sockaddr_storage *addr, socklen_t addrlen, struct udp_sink* sink)
+{
+ struct addr_port* client = g_new(struct addr_port, 1);
+ if(!client) return;
+
+ switch(addr->ss_family)
+ {
+ case AF_INET: client->type_ = IPv4; client->port_ = ntohs(((struct sockaddr_in*)addr)->sin_port); break;
+ case AF_INET6: client->type_ = IPv6; client->port_ = ntohs(((struct sockaddr_in6*)addr)->sin6_port); break;
+ default: return;
+ }
+
+ int errcode = getnameinfo((struct sockaddr *)addr, addrlen, client->addr_, sizeof(client->addr_), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV);
+ if (errcode != 0) {
+ log_printf(WARNING, "getnameinfo() error: %s", gai_strerror(errcode));
+ return;
+ }
+ gchar* name = gst_element_get_name(sink->udp_);
+ if(!g_list_find_custom(sink->clients_, client, cmp_addr_port)) {
+ log_printf(INFO, "adding host %s%c%d to list of receivers for element %s", client->addr_, client->type_ == IPv4 ? ':' : '.', client->port_, name);
+ g_signal_emit_by_name(G_OBJECT(sink->udp_), "add", client->addr_, client->port_, NULL);
+ sink->clients_ = g_list_append(sink->clients_, client);
+ } else {
+ log_printf(DEBUG, "not adding host %s%c%d to list of receivers for element %s - already added", client->addr_, client->type_ == IPv4 ? ':' : '.', client->port_, name);
+ g_free(client);
+ }
+ g_free(name);
+}
+
+static void udp_remove_client(struct sockaddr_storage *addr, socklen_t addrlen, struct udp_sink* sink)
+{
+ // TODO: implement this!
+ gchar* name = gst_element_get_name(sink->udp_);
+ log_printf(ERROR, "removing client from %s failed! - removing not yet implemented!", name);
+ g_free(name);
+}
+
+#define UDP_PROTO_MAGIC "SYDRA:"
+#define UDP_PROTO_MAGIC_LEN (sizeof(UDP_PROTO_MAGIC)-1)
+#define UDP_PROTO_CMD_ADD_CLIENT "add_client\n"
+#define UDP_PROTO_CMD_ADD_CLIENT_LEN (sizeof(UDP_PROTO_CMD_ADD_CLIENT)-1)
+#define UDP_PROTO_CMD_RM_CLIENT "remove_client\n"
+#define UDP_PROTO_CMD_RM_CLIENT_LEN (sizeof(UDP_PROTO_CMD_RM_CLIENT)-1)
+
+static gboolean on_udp_desc_ready(gint fd, GIOCondition cond, gpointer user_data)
+{
+ struct udp_sink* sink = (struct udp_sink*)user_data;
+ if(!sink || !(sink->udp_)) {
+ log_printf(WARNING, "File descriptor %d is ready for reading - but supplied element is NULL removing callback", fd);
+ return FALSE;
+ }
+
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ u_int8_t buf[2048];
+ ssize_t bytes = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addrlen);
+ if(bytes < 1) {
+ if(errno == EINTR)
+ return TRUE;
+
+ log_printf(WARNING, "Error while receiving UDP data on fd %d, will remove callback", fd);
+ return FALSE;
+ }
+
+ if(bytes < UDP_PROTO_MAGIC_LEN || memcmp(UDP_PROTO_MAGIC, buf, UDP_PROTO_MAGIC_LEN)) {
+ log_printf(DEBUG, "client discovery: ignoring invalid incoming packet");
+ return TRUE;
+ }
+
+ u_int8_t* cmd = &(buf[UDP_PROTO_MAGIC_LEN]);
+ if(bytes == (UDP_PROTO_MAGIC_LEN+UDP_PROTO_CMD_ADD_CLIENT_LEN) &&
+ !memcmp(UDP_PROTO_CMD_ADD_CLIENT, cmd, UDP_PROTO_CMD_ADD_CLIENT_LEN)) {
+ udp_add_client(&addr, addrlen, sink);
+ } else if(bytes == (UDP_PROTO_MAGIC_LEN+UDP_PROTO_CMD_RM_CLIENT_LEN) &&
+ !memcmp(UDP_PROTO_CMD_RM_CLIENT, cmd, UDP_PROTO_CMD_RM_CLIENT_LEN)) {
+ udp_remove_client(&addr, addrlen, sink);
+ } else {
+ log_printf(DEBUG, "client discovery: ignoring invalid command");
+ }
+ return TRUE;
+}
+
+static gboolean attach_udp_descriptor(struct udp_sink* sink, const char* name, const char* prop)
+{
+ GSocket *sock;
+ g_object_get(G_OBJECT(sink->udp_), prop, &sock, NULL);
+ int fd = g_socket_get_fd(sock);
+
+ guint id = g_unix_fd_add(fd, G_IO_IN, on_udp_desc_ready, sink);
+ if(id <= 0) {
+ log_printf(ERROR, "Error while adding %s file descriptor (%d) to main loop", name, fd);
+ return FALSE;
+ }
+ log_printf(DEBUG, "successfully installed callback for %s (fd: %d) for reading (id: %d)", name, fd, id);
+ return TRUE;
+}
+
+gboolean attach_udp_descriptors(struct udp_sinks *sinks)
+{
+ if(!attach_udp_descriptor(&(sinks->rtp_video_), "RTP(video) IPv4", "used-socket") ||
+ !attach_udp_descriptor(&(sinks->rtp_video_), "RTP(video) IPv6", "used-socket-v6") ||
+ !attach_udp_descriptor(&(sinks->rtcp_video_), "RTCP(video) IPv4", "used-socket") ||
+ !attach_udp_descriptor(&(sinks->rtcp_video_), "RTCP(video) IPv6", "used-socket-v6") ||
+ !attach_udp_descriptor(&(sinks->rtp_audio_), "RTP(audio) IPv4", "used-socket") ||
+ !attach_udp_descriptor(&(sinks->rtp_audio_), "RTP(audio) IPv6", "used-socket-v6") ||
+ !attach_udp_descriptor(&(sinks->rtcp_audio_), "RTCP(audio) IPv4", "used-socket") ||
+ !attach_udp_descriptor(&(sinks->rtcp_audio_), "RTCP(audio) IPv6", "used-socket-v6")) {
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/src/udp.h b/src/udp.h
new file mode 100644
index 0000000..dcdc5ca
--- /dev/null
+++ b/src/udp.h
@@ -0,0 +1,43 @@
+/*
+ * 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@spreadspace.org>
+ *
+ * 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/>.
+ *
+ * In addition, as a special exception, the copyright holders hereby
+ * grant permission for non-GPL-compatible GStreamer plugins to be used
+ * and distributed together with GStreamer and sydra.
+ * This permission goes above and beyond the permissions granted by the
+ * GPL license sydra is covered by.
+ */
+
+#ifndef SYDRA_udp_h_INCLUDED
+#define SYDRA_udp_h_INCLUDED
+
+#include "datatypes.h"
+
+gboolean attach_udp_descriptors(struct udp_sinks *sinks);
+
+#endif