Add zeroconf/mdns support

This commit is contained in:
Robin Gareus 2022-12-02 13:32:08 +01:00
parent aae15e3c90
commit c53b19c039
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
6 changed files with 260 additions and 1 deletions

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2022 Robin Gareus <robin@gareus.org>
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cstdint>
#include <string>
#ifdef __APPLE__
#include <dns_sd.h>
#include <glibmm/iochannel.h>
#include <glibmm/main.h>
#endif
#include "ardour/libardour_visibility.h"
#include "ardour/system_exec.h"
namespace ARDOUR {
class LIBARDOUR_API ZeroConf
{
public:
ZeroConf (std::string const& type = "_osc._udp", uint16_t port = 3819, std::string const& host = "");
~ZeroConf ();
private:
bool start ();
void stop ();
std::string _type;
uint16_t _port;
std::string _host;
#ifdef __APPLE__
static gboolean event (GIOChannel*, GIOCondition, gpointer);
DNSServiceRef _ref;
guint _source_id;
GIOChannel* _gio_channel;
#else
SystemExec* _avahi;
#endif
};
}; // namespace ARDOUR

View File

@ -282,7 +282,8 @@ libardour_sources = [
'vca_manager.cc',
'video_tools_paths.cc',
'vumeterdsp.cc',
'worker.cc'
'worker.cc',
'zeroconf.cc'
]
def options(opt):

166
libs/ardour/zeroconf.cc Normal file
View File

@ -0,0 +1,166 @@
/*
* Copyright (C) 2022 Robin Gareus <robin@gareus.org>
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/file_utils.h"
#include "ardour/filesystem_paths.h"
#include "ardour/zeroconf.h"
#include "pbd/i18n.h"
using namespace ARDOUR;
ZeroConf::ZeroConf (std::string const& type, uint16_t port, std::string const& host)
: _type (type)
, _port (port)
, _host (host)
#ifdef __APPLE__
, _source_id (0)
, _gio_channel (NULL)
#else
, _avahi (NULL)
#endif
{
start ();
}
ZeroConf::~ZeroConf ()
{
stop ();
}
#ifdef __APPLE__
void
ZeroConf::stop ()
{
if (_gio_channel) {
g_source_remove (_source_id);
g_io_channel_unref (_gio_channel);
}
DNSServiceRefDeallocate (_ref);
}
static void
dns_callback (DNSServiceRef sdref,
DNSServiceFlags flags,
DNSServiceErrorType errorCode,
const char* name,
const char* regtype,
const char* domain, void* context)
{
if (errorCode == kDNSServiceErr_NoError) {
PBD::info << string_compose (_("ZeroConf registered: %1 %2 %3"), name, regtype, domain) << endmsg;
} else {
PBD::info << _("ZeroConf registration failed") << endmsg;
}
}
gboolean
ZeroConf::event (GIOChannel* source,
GIOCondition condition,
gpointer data)
{
ZeroConf* self = reinterpret_cast<ZeroConf*> (data);
// assert (_fd == g_io_channel_unix_get_fd (source));
if (condition & ~G_IO_IN) {
/* remove on error */
return false;
} else {
if (DNSServiceProcessResult (self->_ref) != kDNSServiceErr_NoError) {
/* ZeroConf Error in data callback */
return false;
}
return true;
}
}
bool
ZeroConf::start ()
{
if (kDNSServiceErr_NoError != DNSServiceRegister (&_ref, /*flags*/ 0, /*interfaceIndex*/ 0, /*name*/ NULL, _type.c_str (),
/*domain*/ NULL, _host.empty () ? NULL : _host.c_str (), g_htons (_port),
/*txtlen*/ 0, /*TXT*/ NULL, dns_callback, this)) {
return false;
}
int fd = DNSServiceRefSockFD (_ref);
_gio_channel = g_io_channel_unix_new (fd);
_source_id = g_io_add_watch (_gio_channel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_HUP), ZeroConf::event, this);
return true;
}
#elif defined PLATFORM_WINDOWS
/* in theory dns_sd API also works on Windows 10+
* windns.h and dnsapi.dll
*/
bool
ZeroConf::start ()
{
return false;
}
bool
ZeroConf::stop ()
{
}
#else
bool
ZeroConf::start ()
{
std::string avahi_exec;
PBD::Searchpath sp (ARDOUR::ardour_dll_directory ());
if (!PBD::find_file (sp, "ardour-avahi.sh", avahi_exec)) {
PBD::warning << "ardour-avahi.sh was not found." << endmsg;
return false;
}
char** argp;
char tmp[128];
argp = (char**)calloc (5, sizeof (char*));
argp[0] = strdup (avahi_exec.c_str ());
snprintf (tmp, sizeof (tmp), "%d", _port);
argp[1] = strdup (tmp);
argp[2] = strdup (_type.c_str ());
snprintf (tmp, sizeof (tmp), "%d", getpid ());
argp[3] = strdup (tmp);
argp[4] = 0;
_avahi = new ARDOUR::SystemExec (avahi_exec, argp);
if (_avahi->start (SystemExec::ShareWithParent)) {
return false;
}
return false;
}
void
ZeroConf::stop ()
{
ARDOUR::SystemExec* tmp = _avahi;
_avahi = 0;
delete tmp;
}
#endif

24
tools/avahi.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
set -e
test -n "`which avahi-publish`"
test -n "`which tail`"
PORT=$1
TYPE=$2
test -n "$PORT"
test -n "$TYPE"
if test -n "$3"; then
PARENT_PID=$3
else
PARENT_PID=$$
fi
avahi-publish -s Ardour-$PARENT_PID "$TYPE" "$PORT" &
CHILD_PID=$!
trap "kill -- $CHILD_PID" EXIT
tail --pid=$PARENT_PID -f 2>/dev/null

View File

@ -506,6 +506,9 @@ EOF
chmod +x $APPLIB/ardour-util.sh
fi
cp $BUILD_ROOT/avahi.sh $APPLIB/ardour-avahi.sh
chmod +x $APPLIB/ardour-avahi.sh
OURLIBDIR=$BUILD_ROOT/libs
OURLIBS=$OURLIBDIR/ctrl-interface/midi_surface:$OURLIBDIR/ctrl-interface/control_protocol:$OURLIBDIR/ardour:$OURLIBDIR/midi++2:$OURLIBDIR/pbd:$OURLIBDIR/gtkmm2ext:$OURLIBDIR/glibmm2:$OURLIBDIR/canvas:$OURLIBDIR/widgets:$OURLIBDIR/waveview:$OURLIBDIR/evoral:$OURLIBDIR/evoral/src/libsmf:$OURLIBDIR/audiographer:$OURLIBDIR/temporal:$OURLIBDIR/libltc:$OURLIBDIR/qm-dsp:$OURLIBDIR/ardouralsautil:$OURLIBDIR/ptformat:$BUILD_ROOT/gtk2_ardour

View File

@ -10,6 +10,7 @@ import platform as PLATFORM
from waflib.Tools import winres
from waflib.Build import Context
from waflib.Build import BuildContext
import waflib.Utils as Utils
# Fixup OSX 10.5/10.6 builds
# prefer gcc, g++ 4.x over ancient clang-1.5
@ -1619,6 +1620,12 @@ def build(bld):
bld.recurse('tools/sanity_check')
bld.recurse('tools/gccabicheck')
obj = bld(features = 'subst')
obj.source = 'tools/avahi.sh'
obj.target = 'libs/ardour-avahi.sh'
obj.chmod = Utils.O755
obj.install_path = bld.env['LIBDIR']
bld.recurse('libs/clearlooks-newer')
for i in children: