From 0e226cc34ba9680823b815f260d1d0ce6ad2c8d2 Mon Sep 17 00:00:00 2001 From: John Maguire Date: Wed, 16 Jan 2013 14:56:31 +0100 Subject: [PATCH] Add mDNS service publishing on Linux for the remote control. --- src/CMakeLists.txt | 36 ++++++++++- src/networkremote/avahi.cpp | 96 +++++++++++++++++++++++++++++ src/networkremote/avahi.h | 15 +++++ src/networkremote/networkremote.cpp | 9 ++- src/networkremote/zeroconf.cpp | 23 +++++++ src/networkremote/zeroconf.h | 22 +++++++ 6 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 src/networkremote/avahi.cpp create mode 100644 src/networkremote/avahi.h create mode 100644 src/networkremote/zeroconf.cpp create mode 100644 src/networkremote/zeroconf.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3b6284203..f343a360a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -213,12 +213,13 @@ set(SOURCES musicbrainz/chromaprinter.cpp musicbrainz/musicbrainzclient.cpp musicbrainz/tagfetcher.cpp - - networkremote/networkremotehelper.cpp - networkremote/networkremote.cpp + networkremote/incomingdataparser.cpp + networkremote/networkremote.cpp + networkremote/networkremotehelper.cpp networkremote/outgoingdatacreator.cpp networkremote/remoteclient.cpp + networkremote/zeroconf.cpp playlist/dynamicplaylistcontrols.cpp playlist/playlist.cpp @@ -905,6 +906,34 @@ if(HAVE_DBUS) dbus/org.gnome.SettingsDaemon.MediaKeys.xml dbus/gnomesettingsdaemon) + # org.freedesktop.Avahi.Server interface + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.cpp + ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.h + COMMAND ${QT_DBUSXML2CPP_EXECUTABLE} + dbus/org.freedesktop.Avahi.Server.xml + -p ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver + -i dbus/metatypes.h + DEPENDS dbus/org.freedesktop.Avahi.Server.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + list(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.h) + list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahiserver.cpp) + + # org.freedesktop.Avahi.EntryGroup interface + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.cpp + ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.h + COMMAND ${QT_DBUSXML2CPP_EXECUTABLE} + dbus/org.freedesktop.Avahi.EntryGroup.xml + -p ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup + -i dbus/metatypes.h + DEPENDS dbus/org.freedesktop.Avahi.EntryGroup.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + list(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.h) + list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/dbus/avahientrygroup.cpp) + # DeviceKit DBUS interfaces if(HAVE_DEVICEKIT) qt4_add_dbus_interface(SOURCES @@ -928,6 +957,7 @@ optional_source(HAVE_DBUS core/mpris.cpp core/mpris1.cpp core/mpris2.cpp + networkremote/avahi.cpp ui/dbusscreensaver.cpp HEADERS core/mpris.h diff --git a/src/networkremote/avahi.cpp b/src/networkremote/avahi.cpp new file mode 100644 index 000000000..c00ff6f56 --- /dev/null +++ b/src/networkremote/avahi.cpp @@ -0,0 +1,96 @@ +#include "avahi.h" + +#include + +#include "core/closure.h" +#include "core/logging.h" +#include "dbus/avahientrygroup.h" +#include "dbus/avahiserver.h" + +namespace { + +void LogCommit(QDBusPendingReply<> reply) { + qLog(Debug) << "Remote interface published on Avahi:" << reply.error(); +} + +void Commit(OrgFreedesktopAvahiEntryGroupInterface* interface) { + QDBusPendingReply<> reply = interface->Commit(); + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply); + QObject::connect( + watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + watcher, SLOT(deleteLater())); + QObject::connect( + watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + interface, SLOT(deleteLater())); + NewClosure( + watcher, + SIGNAL(finished(QDBusPendingCallWatcher*)), + &LogCommit, + reply); +} + +void AddService( + const QString domain, + const QString type, + const QString name, + quint16 port, + QDBusPendingReply path_reply) { + if (path_reply.isError()) { + qLog(Warning) + << "Failed to create Avahi entry group:" + << path_reply.error(); + qLog(Info) + << "This might be because 'disable-user-service-publishing'" + << "is set to 'yes' in avahi-daemon.conf"; + return; + } + qLog(Debug) << path_reply.error(); + OrgFreedesktopAvahiEntryGroupInterface* entry_group_interface = + new OrgFreedesktopAvahiEntryGroupInterface( + "org.freedesktop.Avahi", + path_reply.value().path(), + QDBusConnection::systemBus()); + QDBusPendingReply<> reply = entry_group_interface->AddService( + -1, // Interface (all) + -1, // Protocol (v4 & v6) + 0, // Flags + name, // Service name, eg. Clementine + type, // Service type, eg. _clementine._tcp + domain, // Domain, eg. local + QString::null, // Hostname (filled in by Avahi) + port, // Port our service is running on + QList()); // TXT record + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply); + NewClosure( + watcher, + SIGNAL(finished(QDBusPendingCallWatcher*)), + &Commit, + entry_group_interface); + + QObject::connect( + watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + watcher, SLOT(deleteLater())); +} + +} // namespace + +void Avahi::Publish( + const QString& domain, + const QString& type, + const QString& name, + quint16 port) { + OrgFreedesktopAvahiServerInterface server_interface( + "org.freedesktop.Avahi", + "/", + QDBusConnection::systemBus()); + QDBusPendingReply reply = server_interface.EntryGroupNew(); + QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher(reply); + NewClosure( + watcher, + SIGNAL(finished(QDBusPendingCallWatcher*)), + &AddService, + domain, type, name, port, reply); + QObject::connect( + watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + watcher, SLOT(deleteLater())); +} diff --git a/src/networkremote/avahi.h b/src/networkremote/avahi.h new file mode 100644 index 000000000..87786936f --- /dev/null +++ b/src/networkremote/avahi.h @@ -0,0 +1,15 @@ +#ifndef AVAHI_H +#define AVAHI_H + +#include "zeroconf.h" + +class Avahi : public Zeroconf { + public: + virtual void Publish( + const QString& domain, + const QString& type, + const QString& name, + quint16 port); +}; + +#endif // AVAHI_H diff --git a/src/networkremote/networkremote.cpp b/src/networkremote/networkremote.cpp index 423d619bb..606e97747 100644 --- a/src/networkremote/networkremote.cpp +++ b/src/networkremote/networkremote.cpp @@ -15,11 +15,13 @@ along with Clementine. If not, see . */ +#include "networkremote.h" + #include "core/logging.h" #include "covers/currentartloader.h" +#include "networkremote/zeroconf.h" #include "playlist/playlistmanager.h" -#include "networkremote.h" #include #include @@ -87,6 +89,11 @@ void NetworkRemote::StartServer() { server_ipv6_->listen(QHostAddress::AnyIPv6, port_); qLog(Info) << "Listening on port " << port_; + + if (Zeroconf::GetZeroconf()) { + Zeroconf::GetZeroconf()->Publish( + "local", "_clementine._tcp", "Clementine", port_); + } } void NetworkRemote::StopServer() { diff --git a/src/networkremote/zeroconf.cpp b/src/networkremote/zeroconf.cpp new file mode 100644 index 000000000..9acfab86f --- /dev/null +++ b/src/networkremote/zeroconf.cpp @@ -0,0 +1,23 @@ +#include "zeroconf.h" + +#include "config.h" + +#ifdef HAVE_DBUS +#include "avahi.h" +#endif + +Zeroconf* Zeroconf::sInstance = NULL; + +Zeroconf::~Zeroconf() { + +} + +Zeroconf* Zeroconf::GetZeroconf() { + if (!sInstance) { + #ifdef HAVE_DBUS + sInstance = new Avahi; + #endif // HAVE_DBUS + } + + return sInstance; +} diff --git a/src/networkremote/zeroconf.h b/src/networkremote/zeroconf.h new file mode 100644 index 000000000..bd6994250 --- /dev/null +++ b/src/networkremote/zeroconf.h @@ -0,0 +1,22 @@ +#ifndef ZEROCONF_H +#define ZEROCONF_H + +#include + +class Zeroconf { + public: + virtual ~Zeroconf(); + + virtual void Publish( + const QString& domain, + const QString& type, + const QString& name, + quint16 port) = 0; + + static Zeroconf* GetZeroconf(); + + private: + static Zeroconf* sInstance; +}; + +#endif // ZEROCONF_H