add native avahi-client support
requires extra packages on some systems, eg. libavahi-client-dev on Debian/Ubuntu.
This commit is contained in:
@@ -15,6 +15,10 @@ ifdef CONFIG_AO
|
||||
SRCS += audio_ao.c
|
||||
endif
|
||||
|
||||
ifdef CONFIG_AVAHI
|
||||
SRCS += avahi.c
|
||||
endif
|
||||
|
||||
# default target
|
||||
all: shairport
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Embedded Avahi client. This file is part of Shairport.
|
||||
* Copyright (c) James Laird 2013
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
#include <avahi-common/thread-watch.h>
|
||||
#include <avahi-common/error.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
|
||||
static AvahiClient *client = NULL;
|
||||
static AvahiEntryGroup *group = NULL;
|
||||
static AvahiThreadedPoll *tpoll = NULL;
|
||||
|
||||
static char *name = NULL;
|
||||
|
||||
static void egroup_callback(AvahiEntryGroup *g,
|
||||
AvahiEntryGroupState state,
|
||||
AVAHI_GCC_UNUSED void *userdata) {
|
||||
if (state==AVAHI_ENTRY_GROUP_COLLISION)
|
||||
die("service name already exists on network!");
|
||||
if (state==AVAHI_ENTRY_GROUP_FAILURE)
|
||||
die("avahi entry group failure!");
|
||||
}
|
||||
|
||||
static void register_service(AvahiClient *c) {
|
||||
debug(1, "avahi: register_service\n");
|
||||
if (!group)
|
||||
group = avahi_entry_group_new(c, egroup_callback, NULL);
|
||||
if (!group)
|
||||
die("avahi_entry_group_new failed");
|
||||
|
||||
if (!avahi_entry_group_is_empty(group))
|
||||
return;
|
||||
|
||||
int ret;
|
||||
ret = avahi_entry_group_add_service(group,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
0,
|
||||
name,
|
||||
"_raop._tcp",
|
||||
NULL,
|
||||
NULL,
|
||||
config.port,
|
||||
MDNS_RECORD,
|
||||
NULL);
|
||||
if (ret < 0)
|
||||
die("avahi_entry_group_add_service failed");
|
||||
|
||||
ret = avahi_entry_group_commit(group);
|
||||
if (ret < 0)
|
||||
die("avahi_entry_group_commit failed");
|
||||
}
|
||||
|
||||
static void client_callback(AvahiClient *c,
|
||||
AvahiClientState state,
|
||||
AVAHI_GCC_UNUSED void * userdata) {
|
||||
switch (state) {
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
if (group)
|
||||
avahi_entry_group_reset(group);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
register_service(c);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
die("avahi client failure");
|
||||
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int avahi_register(char *srvname) {
|
||||
debug(1, "avahi: avahi_register\n");
|
||||
name = strdup(srvname);
|
||||
|
||||
int err;
|
||||
if (!(tpoll = avahi_threaded_poll_new())) {
|
||||
warn("couldn't create avahi threaded tpoll!");
|
||||
return 0;
|
||||
}
|
||||
if (!(client = avahi_client_new(avahi_threaded_poll_get(tpoll),
|
||||
0,
|
||||
client_callback,
|
||||
NULL,
|
||||
&err))) {
|
||||
warn("couldn't create avahi client: %s!", avahi_strerror(err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (avahi_threaded_poll_start(tpoll) < 0) {
|
||||
warn("couldn't start avahi tpoll thread");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void avahi_unregister(void) {
|
||||
debug(1, "avahi: avahi_unregister\n");
|
||||
if (tpoll)
|
||||
avahi_threaded_poll_stop(tpoll);
|
||||
tpoll = NULL;
|
||||
|
||||
if (name)
|
||||
free(name);
|
||||
name = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef _AVAHI_H
|
||||
#define _AVAHI_H
|
||||
|
||||
int avahi_register(char *srvname);
|
||||
void avahi_unregister(void);
|
||||
|
||||
#endif // _AVAHI_H
|
||||
@@ -26,6 +26,16 @@ else
|
||||
echo libao not found
|
||||
fi
|
||||
|
||||
if pkg-config avahi-client 2>/dev/null; then
|
||||
CFLAGS="${CFLAGS} `pkg-config --cflags avahi-client`"
|
||||
LDFLAGS="${LDFLAGS} `pkg-config --libs avahi-client`"
|
||||
echo "#define CONFIG_AVAHI" >> config.h
|
||||
echo "CONFIG_AVAHI=yes" >> config.mk
|
||||
echo avahi-client found
|
||||
else
|
||||
echo avahi-client not found
|
||||
fi
|
||||
|
||||
echo "CFLAGS+=${CFLAGS}" >> config.mk
|
||||
echo "LDFLAGS+=${LDFLAGS}" >> config.mk
|
||||
|
||||
|
||||
@@ -29,25 +29,26 @@
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#ifdef CONFIG_AVAHI
|
||||
#include "avahi.h"
|
||||
#endif
|
||||
|
||||
int mdns_pid = 0;
|
||||
|
||||
void mdns_unregister(void) {
|
||||
#ifdef CONFIG_AVAHI
|
||||
avahi_unregister();
|
||||
#endif
|
||||
|
||||
if (mdns_pid)
|
||||
kill(mdns_pid, SIGTERM);
|
||||
mdns_pid = 0;
|
||||
}
|
||||
|
||||
void mdns_register(void) {
|
||||
if (mdns_pid)
|
||||
die("attempted to register with mDNS twice");
|
||||
|
||||
// XXX todo: native avahi support, if available at compile time
|
||||
|
||||
if ((mdns_pid = fork()))
|
||||
return;
|
||||
|
||||
char *mdns_apname = malloc(strlen(config.apname) + 14);
|
||||
char *p = mdns_apname;
|
||||
int i;
|
||||
@@ -58,15 +59,20 @@ void mdns_register(void) {
|
||||
*p++ = '@';
|
||||
strcpy(p, config.apname);
|
||||
|
||||
#ifdef CONFIG_AVAHI
|
||||
if (avahi_register(mdns_apname))
|
||||
return;
|
||||
warn("avahi_register failed, falling back to external programs");
|
||||
#endif
|
||||
|
||||
if ((mdns_pid = fork()))
|
||||
return;
|
||||
|
||||
char mdns_port[6];
|
||||
sprintf(mdns_port, "%d", config.port);
|
||||
|
||||
#define RECORD "tp=UDP", "sm=false", "ek=1", "et=0,1", "cn=0,1", "ch=2", \
|
||||
"ss=16", "sr=44100", "vn=3", "txtvers=1", \
|
||||
config.password ? "pw=true" : "pw=false"
|
||||
|
||||
char *argv[] = {
|
||||
NULL, mdns_apname, "_raop._tcp", mdns_port, RECORD, NULL
|
||||
NULL, mdns_apname, "_raop._tcp", mdns_port, MDNS_RECORD, NULL
|
||||
};
|
||||
|
||||
argv[0] = "avahi-publish-service";
|
||||
@@ -76,7 +82,7 @@ void mdns_register(void) {
|
||||
execvp(argv[0], argv);
|
||||
|
||||
char *mac_argv[] = {"dns-sd", "-R", mdns_apname, "_raop._tcp", ".",
|
||||
mdns_port, RECORD, NULL};
|
||||
mdns_port, MDNS_RECORD, NULL};
|
||||
execvp(mac_argv[0], mac_argv);
|
||||
|
||||
die("Could not establish mDNS advertisement!");
|
||||
|
||||
Reference in New Issue
Block a user