diff --git a/libs/ardour/ardour/zeroconf.h b/libs/ardour/ardour/zeroconf.h new file mode 100644 index 0000000000..436698b1a0 --- /dev/null +++ b/libs/ardour/ardour/zeroconf.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 Robin Gareus + * + * 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 +#include + +#ifdef __APPLE__ +#include +#include +#include +#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 diff --git a/libs/ardour/wscript b/libs/ardour/wscript index f676f11130..d440710c83 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -282,7 +282,8 @@ libardour_sources = [ 'vca_manager.cc', 'video_tools_paths.cc', 'vumeterdsp.cc', - 'worker.cc' + 'worker.cc', + 'zeroconf.cc' ] def options(opt): diff --git a/libs/ardour/zeroconf.cc b/libs/ardour/zeroconf.cc new file mode 100644 index 0000000000..721ff3d584 --- /dev/null +++ b/libs/ardour/zeroconf.cc @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 Robin Gareus + * + * 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 (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 diff --git a/tools/avahi.sh b/tools/avahi.sh new file mode 100755 index 0000000000..15953a41e9 --- /dev/null +++ b/tools/avahi.sh @@ -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 diff --git a/tools/linux_packaging/build b/tools/linux_packaging/build index 095f520743..9b31e7f2c3 100755 --- a/tools/linux_packaging/build +++ b/tools/linux_packaging/build @@ -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 diff --git a/wscript b/wscript index 05f271c91f..044766011a 100644 --- a/wscript +++ b/wscript @@ -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: