]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
The HTSP service is now announced via AVAHI (mDNS service discovery)
authorAndreas Öman <andreas@lonelycoder.com>
Mon, 10 Aug 2009 19:06:16 +0000 (19:06 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Mon, 10 Aug 2009 19:06:16 +0000 (19:06 +0000)
Makefile
configure
debian/changelog
src/avahi.c [new file with mode: 0644]
src/avahi.h [new file with mode: 0644]
src/main.c
support/configure.inc

index ea114915e3bc3304297ab66944597c7fe581e0bd..b099119dc7b0e6f9c281806a33939d6a052d3a4b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -99,6 +99,15 @@ SRCS += src/webui/webui.c \
        src/webui/extjs.c \
        src/webui/simpleui.c \
 
+#
+# AVAHI interface
+# 
+
+SRCS-$(CONFIG_AVAHI) += src/avahi.c
+
+${BUILDDIR}/src/avahi.o : CFLAGS = \
+                      $(shell pkg-config --cflags avahi-client) -Wall -Werror
+
 # Various transformations
 SRCS  += $(SRCS-yes)
 DLIBS += $(DLIBS-yes)
index 54d80aae356c35245e9f4503dba484d517ff6ce4..2c6cbfedf438abbc972604a5be4583988594b709 100755 (executable)
--- a/configure
+++ b/configure
@@ -35,6 +35,7 @@ show_help(){
 }
 
 enable cwc
+enable avahi
 
 for opt do
   optval="${opt#*=}"
@@ -91,6 +92,21 @@ fi
 
 echo >>${CONFIG_MAK} $CC_CONFIG_MAK 
 
+#
+# AVAHI
+#
+if enabled avahi; then
+    if pkg-config avahi-client; then
+       # CFLAGS are included by Makefile
+       echo >>${CONFIG_MAK} "LDFLAGS_cfg += " `pkg-config --libs avahi-client`
+       echo "Using AVAHI client:    `pkg-config --modversion avahi-client`"
+    else
+       echo "avahi-client not found. Unable to build with AVAHI support."
+       echo "To compile without it, configure with: --disable-avahi"
+       die
+    fi
+fi
+
 #
 # configure ffmpeg
 #
index eac361dd85daa607efdb805d9a0dfde233771e9e..92fd9260fb32817cce9695f31a3af448e2768676 100644 (file)
@@ -6,6 +6,8 @@ hts-tvheadend (2.5) hts; urgency=low
   * If XMLTV grabbing was disabled tvheadend would spin in a 100% CPU loop.
     This is now fixed.
 
+  * The HTSP service is now announced via AVAHI (mDNS service discovery)
+
 hts-tvheadend (2.4) hts; urgency=low
 
   * Due to a bug, the polarisation of DVB-S muxes was not correctly
diff --git a/src/avahi.c b/src/avahi.c
new file mode 100644 (file)
index 0000000..6faad26
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *  AVAHI service publisher
+ *  Copyright (C) 2009 Andreas Öman
+ *
+ *  This program 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
+ *  (at your option) any later version.
+ *
+ *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/***
+  This file is part of avahi.
+
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+
+  avahi 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 Lesser General
+  Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+
+#include <avahi-common/alternative.h>
+#include <avahi-common/simple-watch.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/error.h>
+#include <avahi-common/timeval.h>
+
+#include "tvhead.h"
+#include "avahi.h"
+
+static AvahiEntryGroup *group = NULL;
+static char *name = NULL;
+
+static void create_services(AvahiClient *c);
+
+static void
+entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, 
+                    void *userdata)
+{
+  assert(g == group || group == NULL);
+  group = g;
+
+  /* Called whenever the entry group state changes */
+
+  switch (state) {
+  case AVAHI_ENTRY_GROUP_ESTABLISHED :
+    /* The entry group has been established successfully */
+    tvhlog(LOG_INFO, "AVAHI",
+          "Service '%s' successfully established.", name);
+    break;
+
+  case AVAHI_ENTRY_GROUP_COLLISION : {
+    char *n;
+
+    /* A service name collision with a remote service
+     * happened. Let's pick a new name */
+    n = avahi_alternative_service_name(name);
+    avahi_free(name);
+    name = n;
+    
+    tvhlog(LOG_ERR, "AVAHI",
+          "Service name collision, renaming service to '%s'", name);
+
+    /* And recreate the services */
+    create_services(avahi_entry_group_get_client(g));
+    break;
+  }
+
+  case AVAHI_ENTRY_GROUP_FAILURE :
+     tvhlog(LOG_ERR, "AVAHI",
+           "Entry group failure: %s", 
+           avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+    break;
+
+  case AVAHI_ENTRY_GROUP_UNCOMMITED:
+  case AVAHI_ENTRY_GROUP_REGISTERING:
+    ;
+  }
+}
+
+
+/**
+ *
+ */
+static void 
+create_services(AvahiClient *c) 
+{
+  char *n;
+  int ret;
+  assert(c);
+
+  /* If this is the first time we're called, let's create a new
+   * entry group if necessary */
+
+  if (!group)
+    if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) {
+      tvhlog(LOG_ERR, "AVAHI",
+            "avahi_enty_group_new() failed: %s", 
+            avahi_strerror(avahi_client_errno(c)));
+      goto fail;
+    }
+
+  /* If the group is empty (either because it was just created, or
+   * because it was reset previously, add our entries.  */
+
+  if (avahi_entry_group_is_empty(group)) {
+     tvhlog(LOG_DEBUG, "AVAHI", "Adding service '%s'", name);
+
+    /* Add the service for IPP */
+    if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, 
+                                            AVAHI_PROTO_UNSPEC, 0, name, 
+                                            "_htsp._tcp", NULL, NULL, 9982,
+                                            NULL)) < 0) {
+
+      if (ret == AVAHI_ERR_COLLISION)
+       goto collision;
+
+      tvhlog(LOG_ERR, "AVAHI",
+            "Failed to add _htsp._tcp service: %s", 
+            avahi_strerror(ret));
+      goto fail;
+    }
+
+    /* Tell the server to register the service */
+    if ((ret = avahi_entry_group_commit(group)) < 0) {
+      tvhlog(LOG_ERR, "AVAHI",
+            "Failed to commit entry group: %s", 
+            avahi_strerror(ret));
+      goto fail;
+    }
+  }
+
+  return;
+
+ collision:
+
+  /* A service name collision with a local service happened. Let's
+   * pick a new name */
+  n = avahi_alternative_service_name(name);
+  avahi_free(name);
+  name = n;
+
+  tvhlog(LOG_ERR, "AVAHI",
+        "Service name collision, renaming service to '%s'", name);
+
+  avahi_entry_group_reset(group);
+
+  create_services(c);
+  return;
+
+ fail:
+  return;
+}
+
+
+/**
+ *
+ */
+static void
+client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
+{
+  assert(c);
+
+  /* Called whenever the client or server state changes */
+
+  switch (state) {
+  case AVAHI_CLIENT_S_RUNNING:
+
+    /* The server has startup successfully and registered its host
+     * name on the network, so it's time to create our services */
+    create_services(c);
+    break;
+
+  case AVAHI_CLIENT_FAILURE:
+    tvhlog(LOG_ERR, "AVAHI", "Client failure: %s", 
+          avahi_strerror(avahi_client_errno(c)));
+    break;
+
+  case AVAHI_CLIENT_S_COLLISION:
+
+    /* Let's drop our registered services. When the server is back
+     * in AVAHI_SERVER_RUNNING state we will register them
+     * again with the new host name. */
+
+  case AVAHI_CLIENT_S_REGISTERING:
+
+    /* The server records are now being established. This
+     * might be caused by a host name change. We need to wait
+     * for our own records to register until the host name is
+     * properly esatblished. */
+
+    if(group)
+      avahi_entry_group_reset(group);
+
+    break;
+
+  case AVAHI_CLIENT_CONNECTING:
+    ;
+  }
+}
+
+
+/**
+ *
+ */
+static void *
+avahi_thread(void *aux)
+{
+  AvahiSimplePoll *asp = avahi_simple_poll_new();
+  const AvahiPoll *ap = avahi_simple_poll_get(asp);
+
+  name = avahi_strdup("Tvheadend");
+
+  avahi_client_new(ap, AVAHI_CLIENT_NO_FAIL, client_callback, NULL, NULL);
+  while((avahi_simple_poll_iterate(asp, -1)) != -1) {}
+
+  return NULL;
+  
+
+}
+
+/**
+ *
+ */
+void
+avahi_init(void)
+{
+  pthread_t tid;
+
+  pthread_create(&tid, NULL, avahi_thread, NULL);
+}
diff --git a/src/avahi.h b/src/avahi.h
new file mode 100644 (file)
index 0000000..891820c
--- /dev/null
@@ -0,0 +1 @@
+void avahi_init(void);
index 251f22e96caf271f39854ac521bf23ec7ea0383e..c62298b210e0606afcc88a08e86953b82a6d09ba 100644 (file)
@@ -51,6 +51,7 @@
 #include "dvr/dvr.h"
 #include "htsp.h"
 #include "rawtsinput.h"
+#include "avahi.h"
 
 #include "parachute.h"
 #include "settings.h"
@@ -354,6 +355,10 @@ main(int argc, char **argv)
   if(join_transport != NULL)
     subscription_dummy_join(join_transport);
 
+#ifdef CONFIG_AVAHI
+  avahi_init();
+#endif
+
   pthread_mutex_unlock(&global_lock);
 
 
index 4f74edf8bd09fce84e1f39e8b5211a91962d3b93..f7671b1c519614b9f29f2c3386f81059689318eb 100644 (file)
@@ -21,6 +21,7 @@ RELEASENAME=`head -n1 ${TOPDIR}/ChangeLog | awk '{print $2}' | sed s/\(// | sed
 
 CONFIG_LIST="
  cwc
+ avahi
 "
 
 die() {