From fbf4c9126a576cb21585fe2218a7b5d5584935ce Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Fri, 14 Oct 2016 11:42:16 +0200
Subject: [PATCH 01/24] server compiles on macOS
---
server/Makefile | 20 ++++++++++++++++----
server/publishBonjour.cpp | 33 +++++++++++++++++++++++++++++++++
server/publishBonjour.h | 37 +++++++++++++++++++++++++++++++++++++
server/snapServer.cpp | 8 ++++++--
4 files changed, 92 insertions(+), 6 deletions(-)
create mode 100644 server/publishBonjour.cpp
create mode 100644 server/publishBonjour.h
diff --git a/server/Makefile b/server/Makefile
index ab362759..48bb2025 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -9,7 +9,8 @@ else
TARGET_DIR ?= /usr
endif
-CXXFLAGS += -std=c++0x -Wall -Wno-unused-function -O3 -pthread -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -I../externals/asio/asio/include -I../externals/popl/include
+CXXFLAGS += -std=c++0x -Wall -Wno-unused-function -O3 -DASIO_STANDALONE -DVERSION=\"$(VERSION)\" -I. -I.. -I../externals/asio/asio/include -I../externals/popl/include
+OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o json/jsonrpc.o streamreader/streamUri.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o ../common/log.o ../common/sampleFormat.o ../message/pcmChunk.o
ifeq ($(ENDIAN), BIG)
CXXFLAGS += -DIS_BIG_ENDIAN
@@ -18,27 +19,38 @@ endif
ifeq ($(TARGET), OPENWRT)
STRIP = echo
-CXXFLAGS += -DNO_CPP11_STRING
+CXXFLAGS += -DNO_CPP11_STRING -pthread
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -latomic
+OBJ += publishAvahi.o
else ifeq ($(TARGET), FREEBSD)
SHELL = /usr/local/bin/bash
CXX = /usr/local/bin/g++
-CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD
+CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD -pthread
STRIP = strip
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
+OBJ += publishAvahi.o
+
+else ifeq ($(TARGET), MACOS)
+
+CXX = /usr/bin/g++
+CXXFLAGS += -DFREEBSD -DMACOS -DHAS_BONJOUR -Wno-deprecated -I/usr/local/include
+STRIP = strip
+LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -L/usr/local/lib
+OBJ += publishBonjour.o
else
CXX = /usr/bin/g++
STRIP = strip
+CXXFLAGS += -pthread
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
+OBJ += publishAvahi.o
endif
-OBJ = snapServer.o config.o controlServer.o controlSession.o streamServer.o streamSession.o json/jsonrpc.o streamreader/streamUri.o streamreader/streamManager.o streamreader/pcmStream.o streamreader/pipeStream.o streamreader/fileStream.o encoder/encoderFactory.o encoder/flacEncoder.o encoder/pcmEncoder.o encoder/oggEncoder.o publishAvahi.o ../common/log.o ../common/sampleFormat.o ../message/pcmChunk.o
BIN = snapserver
all: $(TARGET)
diff --git a/server/publishBonjour.cpp b/server/publishBonjour.cpp
new file mode 100644
index 00000000..cb07ca3c
--- /dev/null
+++ b/server/publishBonjour.cpp
@@ -0,0 +1,33 @@
+/***
+ This file is part of snapcast
+ Copyright (C) 2014-2016 Johannes Pohl
+
+ 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 .
+***/
+
+
+#include "publishBonjour.h"
+
+
+PublishBonjour::PublishBonjour(const std::string& serviceName)
+{
+}
+
+
+PublishBonjour::~PublishBonjour()
+{
+}
+
+
+
diff --git a/server/publishBonjour.h b/server/publishBonjour.h
new file mode 100644
index 00000000..3d18f59c
--- /dev/null
+++ b/server/publishBonjour.h
@@ -0,0 +1,37 @@
+/***
+ This file is part of snapcast
+ Copyright (C) 2014-2016 Johannes Pohl
+
+ 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 .
+***/
+
+
+#ifndef PUBLISH_BONJOUR_H
+#define PUBLISH_BONJOUR_H
+
+#include
+
+
+class PublishBonjour
+{
+public:
+ PublishBonjour(const std::string& serviceName);
+ ~PublishBonjour();
+
+};
+
+
+#endif
+
+
diff --git a/server/snapServer.cpp b/server/snapServer.cpp
index 2e62094f..ab81720b 100644
--- a/server/snapServer.cpp
+++ b/server/snapServer.cpp
@@ -29,7 +29,11 @@
#include "message/message.h"
#include "encoder/encoderFactory.h"
#include "streamServer.h"
+#if defined(HAS_AVAHI)
#include "publishAvahi.h"
+#elif defined(HAS_BONJOUR)
+#include "publishBonjour.h"
+#endif
#include "config.h"
#include "common/log.h"
@@ -142,13 +146,13 @@ int main(int argc, char* argv[])
setpriority(PRIO_PROCESS, 0, processPriority);
logS(kLogNotice) << "daemon started" << std::endl;
}
-
+#if defined(HAS_AVAHI)
PublishAvahi publishAvahi("Snapcast");
std::vector services;
services.push_back(AvahiService("_snapcast._tcp", settings.port));
services.push_back(AvahiService("_snapcast-jsonrpc._tcp", settings.controlPort));
publishAvahi.publish(services);
-
+#endif
if (settings.bufferMs < 400)
settings.bufferMs = 400;
settings.sampleFormat = sampleFormatValue.getValue();
From 675bd17ab88e5f909ac7b6678e3a52d041befcc7 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Sun, 16 Oct 2016 14:45:50 +0200
Subject: [PATCH 02/24] ZeroConf (Bonjour) for macOS server
---
client/Makefile | 22 +++----
server/Makefile | 25 ++++----
server/publishAvahi.cpp | 6 +-
server/publishAvahi.h | 22 ++-----
server/publishBonjour.cpp | 129 +++++++++++++++++++++++++++++++++++++-
server/publishBonjour.h | 14 ++++-
server/publishmDNS.h | 44 +++++++++++++
server/snapServer.cpp | 16 ++---
8 files changed, 222 insertions(+), 56 deletions(-)
create mode 100755 server/publishmDNS.h
diff --git a/client/Makefile b/client/Makefile
index f39995b2..a55c5acf 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -19,33 +19,33 @@ endif
ifeq ($(TARGET), ANDROID)
-CXX = $(NDK_DIR)/bin/arm-linux-androideabi-g++
-STRIP = $(NDK_DIR)/bin/arm-linux-androideabi-strip
+CXX = $(NDK_DIR)/bin/arm-linux-androideabi-g++
+STRIP = $(NDK_DIR)/bin/arm-linux-androideabi-strip
CXXFLAGS += -pthread -DANDROID -DNO_CPP11_STRING -fPIC -DHAS_TREMOR -DHAS_OPENSL -I$(NDK_DIR)/include
-LDFLAGS = -L$(NDK_DIR)/lib -pie -lvorbisidec -logg -lFLAC -lOpenSLES
+LDFLAGS = -L$(NDK_DIR)/lib -pie -lvorbisidec -logg -lFLAC -lOpenSLES
OBJ += player/openslPlayer.o
else ifeq ($(TARGET), OPENWRT)
-STRIP = echo
+STRIP = echo
CXXFLAGS += -pthread -DNO_CPP11_STRING -DHAS_TREMOR -DHAS_ALSA -DHAS_AVAHI -DHAS_DAEMON
-LDFLAGS = -lasound -lvorbisidec -logg -lFLAC -lavahi-client -lavahi-common -latomic
+LDFLAGS = -lasound -lvorbisidec -logg -lFLAC -lavahi-client -lavahi-common -latomic
OBJ += player/alsaPlayer.o browseAvahi.o
else ifeq ($(TARGET), MACOS)
-CXX = /usr/bin/g++
-STRIP = strip
+CXX = /usr/bin/g++
+STRIP = strip
CXXFLAGS += -DHAS_OGG -DHAS_COREAUDIO -DFREEBSD -DMACOS -DHAS_BONJOUR -I/usr/local/include -Wno-unused-local-typedef -Wno-deprecated
-LDFLAGS = -logg -lvorbis -lFLAC -L/usr/local/lib -framework AudioToolbox -framework CoreFoundation
+LDFLAGS = -logg -lvorbis -lFLAC -L/usr/local/lib -framework AudioToolbox -framework CoreFoundation
OBJ += player/coreAudioPlayer.o browseBonjour.o
else
-CXX = /usr/bin/g++
-STRIP = strip
+CXX = /usr/bin/g++
+STRIP = strip
CXXFLAGS += -pthread -DHAS_OGG -DHAS_ALSA -DHAS_AVAHI -DHAS_DAEMON
-LDFLAGS = -lrt -lasound -logg -lvorbis -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
+LDFLAGS = -lrt -lasound -logg -lvorbis -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
OBJ += player/alsaPlayer.o browseAvahi.o
endif
diff --git a/server/Makefile b/server/Makefile
index 48bb2025..e7dc94cd 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -18,34 +18,33 @@ endif
ifeq ($(TARGET), OPENWRT)
-STRIP = echo
+STRIP = echo
CXXFLAGS += -DNO_CPP11_STRING -pthread
-LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -latomic
+LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -latomic
OBJ += publishAvahi.o
else ifeq ($(TARGET), FREEBSD)
-SHELL = /usr/local/bin/bash
-CXX = /usr/local/bin/g++
+CXX = /usr/local/bin/g++
+STRIP = echo
CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD -pthread
-STRIP = strip
-LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
+LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
OBJ += publishAvahi.o
else ifeq ($(TARGET), MACOS)
-CXX = /usr/bin/g++
+CXX = /usr/bin/g++
+STRIP = strip
CXXFLAGS += -DFREEBSD -DMACOS -DHAS_BONJOUR -Wno-deprecated -I/usr/local/include
-STRIP = strip
-LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -L/usr/local/lib
-OBJ += publishBonjour.o
+LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -L/usr/local/lib
+OBJ += publishBonjour.o
else
-CXX = /usr/bin/g++
-STRIP = strip
+CXX = /usr/bin/g++
+STRIP = strip
CXXFLAGS += -pthread
-LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
+LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
OBJ += publishAvahi.o
endif
diff --git a/server/publishAvahi.cpp b/server/publishAvahi.cpp
index f187cd9a..2b79984d 100644
--- a/server/publishAvahi.cpp
+++ b/server/publishAvahi.cpp
@@ -27,8 +27,8 @@ static AvahiEntryGroup *group;
static AvahiSimplePoll *simple_poll;
static char* name;
-PublishAvahi::PublishAvahi(const std::string& serviceName) :
- client(NULL), serviceName_(serviceName), active_(false)
+PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(serviceName)
+ client(NULL), active_(false)
{
group = NULL;
simple_poll = NULL;
@@ -36,7 +36,7 @@ PublishAvahi::PublishAvahi(const std::string& serviceName) :
}
-void PublishAvahi::publish(const std::vector& services)
+void PublishAvahi::publish(const std::vector& services)
{
this->services = services;
diff --git a/server/publishAvahi.h b/server/publishAvahi.h
index 2e131f14..e6315e44 100644
--- a/server/publishAvahi.h
+++ b/server/publishAvahi.h
@@ -33,36 +33,26 @@
#include
#include
+class PublishAvahi;
-struct AvahiService
-{
- AvahiService(const std::string& name, size_t port, int proto = AVAHI_PROTO_UNSPEC) : name_(name), port_(port), proto_(proto)
- {
- }
+#include "publishmDNS.h"
- std::string name_;
- size_t port_;
- int proto_;
-};
-
-
-class PublishAvahi
+class PublishAvahi : public PublishmDNS
{
public:
PublishAvahi(const std::string& serviceName);
- ~PublishAvahi();
- void publish(const std::vector& services);
+ virtual ~PublishAvahi();
+ virtual void publish(const std::vector& services);
private:
static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata);
static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata);
void create_services(AvahiClient *c);
AvahiClient* client;
- std::string serviceName_;
std::thread pollThread_;
void worker();
std::atomic active_;
- std::vector services;
+ std::vector services;
};
diff --git a/server/publishBonjour.cpp b/server/publishBonjour.cpp
index cb07ca3c..2bb027a6 100644
--- a/server/publishBonjour.cpp
+++ b/server/publishBonjour.cpp
@@ -16,18 +16,145 @@
along with this program. If not, see .
***/
+#include
+#include
#include "publishBonjour.h"
+#include "common/log.h"
+
+typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
-PublishBonjour::PublishBonjour(const std::string& serviceName)
+PublishBonjour::PublishBonjour(const std::string& serviceName) : PublishmDNS(serviceName), active_(false)
{
+/// dns-sd -R Snapcast _snapcast._tcp local 1704
+/// dns-sd -R Snapcast _snapcast-jsonrpc._tcp local 1705
}
PublishBonjour::~PublishBonjour()
{
+ active_ = false;
+ pollThread_.join();
+ for (auto client: clients)
+ {
+ if (client)
+ DNSServiceRefDeallocate(client);
+ }
}
+void PublishBonjour::worker()
+{
+// int dns_sd_fd = client ? DNSServiceRefSockFD(client) : -1;
+ // 1. Set up the fd_set as usual here.
+ // This example client has no file descriptors of its own,
+ // but a real application would call FD_SET to add them to the set here
+ fd_set readfds;
+ FD_ZERO(&readfds);
+
+ std::vector dns_sd_fds;
+ int nfds = -1;
+ for (size_t n=0; n 0)
+ {
+
+ for (size_t n=0; n& services)
+{
+ for (auto service: services)
+ {
+ DNSServiceFlags flags = 0;
+ Opaque16 registerPort = { { static_cast(service.port_ >> 8), static_cast(service.port_ & 0xFF) } };
+ DNSServiceRef client = NULL;
+ DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, this);
+ clients.push_back(client);
+ }
+
+ pollThread_ = std::thread(&PublishBonjour::worker, this);
+}
+
+
+
+
+
+
diff --git a/server/publishBonjour.h b/server/publishBonjour.h
index 3d18f59c..674f0504 100644
--- a/server/publishBonjour.h
+++ b/server/publishBonjour.h
@@ -21,14 +21,24 @@
#define PUBLISH_BONJOUR_H
#include
+#include
+class PublishBonjour;
-class PublishBonjour
+#include "publishmDNS.h"
+
+class PublishBonjour : public PublishmDNS
{
public:
PublishBonjour(const std::string& serviceName);
- ~PublishBonjour();
+ virtual ~PublishBonjour();
+ virtual void publish(const std::vector& services);
+private:
+ std::thread pollThread_;
+ void worker();
+ std::atomic active_;
+ std::vector clients;
};
diff --git a/server/publishmDNS.h b/server/publishmDNS.h
new file mode 100755
index 00000000..9ad667d7
--- /dev/null
+++ b/server/publishmDNS.h
@@ -0,0 +1,44 @@
+#ifndef PUBLISH_MDNS_H
+#define PUBLISH_MDNS_H
+
+#include
+#include
+
+
+struct mDNSService
+{
+ mDNSService(const std::string& name, size_t port) : name_(name), port_(port)
+ {
+ }
+
+ std::string name_;
+ size_t port_;
+};
+
+
+class PublishmDNS
+{
+public:
+ PublishmDNS(const std::string& serviceName) : serviceName_(serviceName)
+ {
+ }
+
+ virtual ~PublishmDNS()
+ {
+ }
+
+ virtual void publish(const std::vector& services) = 0;
+
+protected:
+ std::string serviceName_;
+};
+
+#if defined(HAS_AVAHI)
+#include "publishAvahi.h"
+typedef PublishAvahi PublishZeroConf;
+#elif defined(HAS_BONJOUR)
+#include "publishBonjour.h"
+typedef PublishBonjour PublishZeroConf;
+#endif
+
+#endif
diff --git a/server/snapServer.cpp b/server/snapServer.cpp
index ab81720b..68807cab 100644
--- a/server/snapServer.cpp
+++ b/server/snapServer.cpp
@@ -29,10 +29,8 @@
#include "message/message.h"
#include "encoder/encoderFactory.h"
#include "streamServer.h"
-#if defined(HAS_AVAHI)
-#include "publishAvahi.h"
-#elif defined(HAS_BONJOUR)
-#include "publishBonjour.h"
+#if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
+#include "publishmDNS.h"
#endif
#include "config.h"
#include "common/log.h"
@@ -146,13 +144,11 @@ int main(int argc, char* argv[])
setpriority(PRIO_PROCESS, 0, processPriority);
logS(kLogNotice) << "daemon started" << std::endl;
}
-#if defined(HAS_AVAHI)
- PublishAvahi publishAvahi("Snapcast");
- std::vector services;
- services.push_back(AvahiService("_snapcast._tcp", settings.port));
- services.push_back(AvahiService("_snapcast-jsonrpc._tcp", settings.controlPort));
- publishAvahi.publish(services);
+#if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
+ PublishZeroConf publishZeroConfg("Snapcast");
+ publishZeroConfg.publish({mDNSService("_snapcast._tcp", settings.port), mDNSService("_snapcast-jsonrpc._tcp", settings.controlPort)});
#endif
+
if (settings.bufferMs < 400)
settings.bufferMs = 400;
settings.sampleFormat = sampleFormatValue.getValue();
From c6fcadfbd567e8f259cb5dfb27e5be18fe1a43f9 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Sun, 16 Oct 2016 14:46:21 +0200
Subject: [PATCH 03/24] by ref
---
server/config.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/server/config.h b/server/config.h
index 0929b03d..e25090f8 100644
--- a/server/config.h
+++ b/server/config.h
@@ -30,7 +30,7 @@
using json = nlohmann::json;
template
-T jGet(json j, const std::string& what, const T& def)
+T jGet(const json& j, const std::string& what, const T& def)
{
try
{
From 7715f3bbd3ec482b6e8f4772f49ef9eda004e844 Mon Sep 17 00:00:00 2001
From: badaix
Date: Sun, 16 Oct 2016 15:04:13 +0200
Subject: [PATCH 04/24] fixed Avahi
---
server/Makefile | 6 +++---
server/publishAvahi.cpp | 18 ++++++++----------
server/publishAvahi.h | 4 ++--
3 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/server/Makefile b/server/Makefile
index e7dc94cd..74a9528b 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -19,7 +19,7 @@ endif
ifeq ($(TARGET), OPENWRT)
STRIP = echo
-CXXFLAGS += -DNO_CPP11_STRING -pthread
+CXXFLAGS += -DNO_CPP11_STRING -DHAS_AVAHI -pthread
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -latomic
OBJ += publishAvahi.o
@@ -27,7 +27,7 @@ else ifeq ($(TARGET), FREEBSD)
CXX = /usr/local/bin/g++
STRIP = echo
-CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD -pthread
+CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD -DHAS_AVAHI -pthread
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
OBJ += publishAvahi.o
@@ -43,7 +43,7 @@ else
CXX = /usr/bin/g++
STRIP = strip
-CXXFLAGS += -pthread
+CXXFLAGS += -DHAS_AVAHI -pthread
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
OBJ += publishAvahi.o
diff --git a/server/publishAvahi.cpp b/server/publishAvahi.cpp
index 2b79984d..675cdbb2 100644
--- a/server/publishAvahi.cpp
+++ b/server/publishAvahi.cpp
@@ -27,8 +27,8 @@ static AvahiEntryGroup *group;
static AvahiSimplePoll *simple_poll;
static char* name;
-PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(serviceName)
- client(NULL), active_(false)
+PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(serviceName),
+ client_(NULL), active_(false)
{
group = NULL;
simple_poll = NULL;
@@ -40,9 +40,6 @@ void PublishAvahi::publish(const std::vector& services)
{
this->services = services;
- AvahiClient *client = NULL;
- int error;
-
/* Allocate main loop object */
if (!(simple_poll = avahi_simple_poll_new()))
{
@@ -50,10 +47,11 @@ void PublishAvahi::publish(const std::vector& services)
}
/* Allocate a new client */
- client = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
+ int error;
+ client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
/* Check wether creating the client object succeeded */
- if (!client)
+ if (!client_)
{
logE << "Failed to create client: " << avahi_strerror(error) << "\n";
}
@@ -74,8 +72,8 @@ PublishAvahi::~PublishAvahi()
active_ = false;
pollThread_.join();
- if (client)
- avahi_client_free(client);
+ if (client_)
+ avahi_client_free(client_);
if (simple_poll)
avahi_simple_poll_free(simple_poll);
@@ -174,7 +172,7 @@ void PublishAvahi::create_services(AvahiClient *c)
/* Add the same service for BSD LPR */
for (size_t n=0; n active_;
std::vector services;
};
From eb021d84c2821c12fc1dcd8ba23ca51a42418c39 Mon Sep 17 00:00:00 2001
From: badaix
Date: Mon, 17 Oct 2016 09:05:51 +0200
Subject: [PATCH 05/24] macOS support warning
---
client/snapClient.cpp | 2 +-
server/publishAvahi.cpp | 10 +++++-----
server/snapServer.cpp | 7 +++----
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/client/snapClient.cpp b/client/snapClient.cpp
index 98e7803b..c62aca11 100644
--- a/client/snapClient.cpp
+++ b/client/snapClient.cpp
@@ -67,7 +67,7 @@ PcmDevice getPcmDevice(const std::string& soundcard)
int main (int argc, char **argv)
{
#ifdef MACOS
-#pragma message "Warning: the Mac OS support is experimental and might not be maintained"
+#pragma message "Warning: the macOS support is experimental and might not be maintained"
#endif
try
{
diff --git a/server/publishAvahi.cpp b/server/publishAvahi.cpp
index 675cdbb2..64e272a4 100644
--- a/server/publishAvahi.cpp
+++ b/server/publishAvahi.cpp
@@ -72,13 +72,13 @@ PublishAvahi::~PublishAvahi()
active_ = false;
pollThread_.join();
- if (client_)
- avahi_client_free(client_);
+ if (client_)
+ avahi_client_free(client_);
- if (simple_poll)
- avahi_simple_poll_free(simple_poll);
+ if (simple_poll)
+ avahi_simple_poll_free(simple_poll);
- avahi_free(name);
+ avahi_free(name);
}
diff --git a/server/snapServer.cpp b/server/snapServer.cpp
index 68807cab..c35cc36f 100644
--- a/server/snapServer.cpp
+++ b/server/snapServer.cpp
@@ -45,6 +45,9 @@ using namespace popl;
int main(int argc, char* argv[])
{
+#ifdef MACOS
+#pragma message "Warning: the macOS support is experimental and might not be maintained"
+#endif
try
{
StreamServerSettings settings;
@@ -181,7 +184,3 @@ int main(int argc, char* argv[])
return 0;
}
-
-
-
-
From 8b5c22120c1f9623bb658dea0e66502e3d8e21a9 Mon Sep 17 00:00:00 2001
From: badaix
Date: Mon, 17 Oct 2016 09:09:09 +0200
Subject: [PATCH 06/24] fprintf => logE
---
server/publishBonjour.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/publishBonjour.cpp b/server/publishBonjour.cpp
index 2bb027a6..1bc78cb6 100644
--- a/server/publishBonjour.cpp
+++ b/server/publishBonjour.cpp
@@ -90,7 +90,7 @@ void PublishBonjour::worker()
DNSServiceErrorType err = DNSServiceProcessResult(clients[n]);
if (err)
{
- fprintf(stderr, "DNSServiceProcessResult returned %d\n", err);
+ logE << "DNSServiceProcessResult returned " << err << "\n";
active_ = false;
}
}
@@ -100,7 +100,7 @@ void PublishBonjour::worker()
// myTimerCallBack();
else if (result < 0)
{
- printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
+ logE << "select() returned " << result << " errno " << errno << " " << strerror(errno) << "\n";
if (errno != EINTR)
active_ = false;
}
From 57b757ac5e95520f1b83801460f88729ae1d2f36 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Mon, 17 Oct 2016 12:10:50 +0200
Subject: [PATCH 07/24] Update build.md
---
doc/build.md | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/doc/build.md b/doc/build.md
index e8686074..15f81d5b 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -104,18 +104,25 @@ Start and stop the server with `sudo service snapserver start` and `sudo service
*Warning: macOS support is experimental*
-Install Xcode from the App Store
-
-###Build Snapclient
-Install the required libs:
+ 1. Install Xcode from the App Store
+ 2. Install [Homebrew](http://brew.sh)
+ 3. Install the required libs:
$ brew install flac libvorbis
+
+###Build Snapclient
`cd` into the Snapclient src-root directory:
$ cd /client
$ make TARGET=MACOS
+###Build Snapserver
+`cd` into the Snapserver src-root directory:
+
+ $ cd /server
+ $ make TARGET=MACOS
+
##Android (Cross compile)
Cross compilation for Android is done with the [Android NDK](http://developer.android.com/tools/sdk/ndk/index.html) on a Linux host machine.
From 7039f29223483afe2466772253d68d654098f01f Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Mon, 17 Oct 2016 12:14:15 +0200
Subject: [PATCH 08/24] Update build.md
---
doc/build.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/doc/build.md b/doc/build.md
index 15f81d5b..a46553a6 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -106,10 +106,11 @@ Start and stop the server with `sudo service snapserver start` and `sudo service
1. Install Xcode from the App Store
2. Install [Homebrew](http://brew.sh)
- 3. Install the required libs:
-
+ 3. Install the required libs
+ ```
$ brew install flac libvorbis
+ ```
###Build Snapclient
`cd` into the Snapclient src-root directory:
From 819c22575e8a88d036c8b224f3306413694ac2d7 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Mon, 17 Oct 2016 12:20:44 +0200
Subject: [PATCH 09/24] Update build.md
---
doc/build.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/build.md b/doc/build.md
index a46553a6..c6db9ce5 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -107,9 +107,9 @@ Start and stop the server with `sudo service snapserver start` and `sudo service
1. Install Xcode from the App Store
2. Install [Homebrew](http://brew.sh)
3. Install the required libs
+
```
$ brew install flac libvorbis
-
```
###Build Snapclient
From 45c12c472f03a8206d67b141124c105944faf51c Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Wed, 19 Oct 2016 09:21:58 +0200
Subject: [PATCH 10/24] moved zeroconf to browseZeroConf dir
---
client/Makefile | 6 +++---
client/{ => browseZeroConf}/browseAvahi.cpp | 0
client/{ => browseZeroConf}/browseAvahi.h | 0
client/{ => browseZeroConf}/browseBonjour.cpp | 0
client/{ => browseZeroConf}/browseBonjour.h | 0
client/{ => browseZeroConf}/browsemDNS.h | 0
client/snapClient.cpp | 2 +-
7 files changed, 4 insertions(+), 4 deletions(-)
rename client/{ => browseZeroConf}/browseAvahi.cpp (100%)
rename client/{ => browseZeroConf}/browseAvahi.h (100%)
rename client/{ => browseZeroConf}/browseBonjour.cpp (100%)
rename client/{ => browseZeroConf}/browseBonjour.h (100%)
rename client/{ => browseZeroConf}/browsemDNS.h (100%)
diff --git a/client/Makefile b/client/Makefile
index a55c5acf..10911397 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -30,7 +30,7 @@ else ifeq ($(TARGET), OPENWRT)
STRIP = echo
CXXFLAGS += -pthread -DNO_CPP11_STRING -DHAS_TREMOR -DHAS_ALSA -DHAS_AVAHI -DHAS_DAEMON
LDFLAGS = -lasound -lvorbisidec -logg -lFLAC -lavahi-client -lavahi-common -latomic
-OBJ += player/alsaPlayer.o browseAvahi.o
+OBJ += player/alsaPlayer.o browseZeroConf/browseAvahi.o
else ifeq ($(TARGET), MACOS)
@@ -38,7 +38,7 @@ CXX = /usr/bin/g++
STRIP = strip
CXXFLAGS += -DHAS_OGG -DHAS_COREAUDIO -DFREEBSD -DMACOS -DHAS_BONJOUR -I/usr/local/include -Wno-unused-local-typedef -Wno-deprecated
LDFLAGS = -logg -lvorbis -lFLAC -L/usr/local/lib -framework AudioToolbox -framework CoreFoundation
-OBJ += player/coreAudioPlayer.o browseBonjour.o
+OBJ += player/coreAudioPlayer.o browseZeroConf/browseBonjour.o
else
@@ -46,7 +46,7 @@ CXX = /usr/bin/g++
STRIP = strip
CXXFLAGS += -pthread -DHAS_OGG -DHAS_ALSA -DHAS_AVAHI -DHAS_DAEMON
LDFLAGS = -lrt -lasound -logg -lvorbis -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
-OBJ += player/alsaPlayer.o browseAvahi.o
+OBJ += player/alsaPlayer.o browseZeroConf/browseAvahi.o
endif
diff --git a/client/browseAvahi.cpp b/client/browseZeroConf/browseAvahi.cpp
similarity index 100%
rename from client/browseAvahi.cpp
rename to client/browseZeroConf/browseAvahi.cpp
diff --git a/client/browseAvahi.h b/client/browseZeroConf/browseAvahi.h
similarity index 100%
rename from client/browseAvahi.h
rename to client/browseZeroConf/browseAvahi.h
diff --git a/client/browseBonjour.cpp b/client/browseZeroConf/browseBonjour.cpp
similarity index 100%
rename from client/browseBonjour.cpp
rename to client/browseZeroConf/browseBonjour.cpp
diff --git a/client/browseBonjour.h b/client/browseZeroConf/browseBonjour.h
similarity index 100%
rename from client/browseBonjour.h
rename to client/browseZeroConf/browseBonjour.h
diff --git a/client/browsemDNS.h b/client/browseZeroConf/browsemDNS.h
similarity index 100%
rename from client/browsemDNS.h
rename to client/browseZeroConf/browsemDNS.h
diff --git a/client/snapClient.cpp b/client/snapClient.cpp
index c62aca11..9b890922 100644
--- a/client/snapClient.cpp
+++ b/client/snapClient.cpp
@@ -21,7 +21,7 @@
#include "popl.hpp"
#include "controller.h"
-#include "browsemDNS.h"
+#include "browseZeroConf/browsemDNS.h"
#ifdef HAS_ALSA
#include "player/alsaPlayer.h"
From ef6aa89222c125d7d3a06000ef744d37f3068c20 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Wed, 19 Oct 2016 09:22:20 +0200
Subject: [PATCH 11/24] moved zeroconf to publishZeroConf dir
---
server/Makefile | 8 +-
server/{ => publishZeroConf}/publishAvahi.cpp | 85 ++++++-------------
server/{ => publishZeroConf}/publishAvahi.h | 2 +-
.../{ => publishZeroConf}/publishBonjour.cpp | 3 +-
server/{ => publishZeroConf}/publishBonjour.h | 0
server/{ => publishZeroConf}/publishmDNS.h | 0
server/snapServer.cpp | 2 +-
7 files changed, 34 insertions(+), 66 deletions(-)
rename server/{ => publishZeroConf}/publishAvahi.cpp (65%)
rename server/{ => publishZeroConf}/publishAvahi.h (97%)
rename server/{ => publishZeroConf}/publishBonjour.cpp (94%)
rename server/{ => publishZeroConf}/publishBonjour.h (100%)
rename server/{ => publishZeroConf}/publishmDNS.h (100%)
diff --git a/server/Makefile b/server/Makefile
index 74a9528b..f9d55e8c 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -21,7 +21,7 @@ ifeq ($(TARGET), OPENWRT)
STRIP = echo
CXXFLAGS += -DNO_CPP11_STRING -DHAS_AVAHI -pthread
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -latomic
-OBJ += publishAvahi.o
+OBJ += publishZeroConf/publishAvahi.o
else ifeq ($(TARGET), FREEBSD)
@@ -29,7 +29,7 @@ CXX = /usr/local/bin/g++
STRIP = echo
CXXFLAGS += -DNO_CPP11_STRING -DFREEBSD -DHAS_AVAHI -pthread
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
-OBJ += publishAvahi.o
+OBJ += publishZeroConf/publishAvahi.o
else ifeq ($(TARGET), MACOS)
@@ -37,7 +37,7 @@ CXX = /usr/bin/g++
STRIP = strip
CXXFLAGS += -DFREEBSD -DMACOS -DHAS_BONJOUR -Wno-deprecated -I/usr/local/include
LDFLAGS = -lvorbis -lvorbisenc -logg -lFLAC -L/usr/local/lib
-OBJ += publishBonjour.o
+OBJ += publishZeroConf/publishBonjour.o
else
@@ -45,7 +45,7 @@ CXX = /usr/bin/g++
STRIP = strip
CXXFLAGS += -DHAS_AVAHI -pthread
LDFLAGS = -lrt -lvorbis -lvorbisenc -logg -lFLAC -lavahi-client -lavahi-common -static-libgcc -static-libstdc++
-OBJ += publishAvahi.o
+OBJ += publishZeroConf/publishAvahi.o
endif
diff --git a/server/publishAvahi.cpp b/server/publishZeroConf/publishAvahi.cpp
similarity index 65%
rename from server/publishAvahi.cpp
rename to server/publishZeroConf/publishAvahi.cpp
index 64e272a4..f1f655ca 100644
--- a/server/publishAvahi.cpp
+++ b/server/publishZeroConf/publishAvahi.cpp
@@ -38,19 +38,20 @@ PublishAvahi::PublishAvahi(const std::string& serviceName) : PublishmDNS(service
void PublishAvahi::publish(const std::vector& services)
{
- this->services = services;
+ services_ = services;
- /* Allocate main loop object */
+ /// Allocate main loop object
if (!(simple_poll = avahi_simple_poll_new()))
{
+ ///TODO: error handling
logE << "Failed to create simple poll object.\n";
}
- /* Allocate a new client */
+ /// Allocate a new client
int error;
client_ = avahi_client_new(avahi_simple_poll_get(simple_poll), AVAHI_CLIENT_IGNORE_USER_CONFIG, client_callback, this, &error);
- /* Check wether creating the client object succeeded */
+ /// Check wether creating the client object succeeded
if (!client_)
{
logE << "Failed to create client: " << avahi_strerror(error) << "\n";
@@ -87,27 +88,26 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState
assert(g == group || group == NULL);
group = g;
- /* Called whenever the entry group state changes */
-
+ /// Called whenever the entry group state changes
switch (state)
{
case AVAHI_ENTRY_GROUP_ESTABLISHED :
- /* The entry group has been established successfully */
+ /// The entry group has been established successfully
logO << "Service '" << name << "' successfully established.\n";
break;
- case AVAHI_ENTRY_GROUP_COLLISION : {
+ case AVAHI_ENTRY_GROUP_COLLISION :
+ {
char *n;
- /* A service name collision with a remote service
- * happened. Let's pick a new name */
+ /// 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;
logO << "Service name collision, renaming service to '" << name << "'\n";
- /* And recreate the services */
+ /// And recreate the services
static_cast(userdata)->create_services(avahi_entry_group_get_client(g));
break;
}
@@ -116,7 +116,7 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState
logE << "Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "\n";
- /* Some kind of failure happened while we were registering our services */
+ /// Some kind of failure happened while we were registering our services
avahi_simple_poll_quit(simple_poll);
break;
@@ -132,9 +132,7 @@ void PublishAvahi::create_services(AvahiClient *c)
int ret;
assert(c);
- /* If this is the first time we're called, let's create a new
- * entry group if necessary */
-
+ /// 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, this)))
@@ -143,54 +141,33 @@ void PublishAvahi::create_services(AvahiClient *c)
goto fail;
}
}
- /* If the group is empty (either because it was just created, or
- * because it was reset previously, add our entries. */
+ /// 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))
{
logO << "Adding service '" << name << "'\n";
- /* Create some random TXT data */
- snprintf(r, sizeof(r), "random=%i", rand());
-
- /* We will now add two services and one subtype to the entry
- * group. The two services have the same name, but differ in
- * the service type (IPP vs. BSD LPR). Only services with the
- * same name should be put in the same entry group. */
-
- /* Add the service for IPP */
-/* if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AVAHI_PUBLISH_UNIQUE, name, "_ipp._tcp", NULL, NULL, 651, "test=blah", r, NULL)) < 0)
+ /// We will now add two services and one subtype to the entry group
+ for (const auto& service: services)
{
-
- if (ret == AVAHI_ERR_COLLISION)
- goto collision;
-
- fprintf(stderr, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
- goto fail;
- }
-*/
- /* Add the same service for BSD LPR */
- for (size_t n=0; n(userdata)->create_services(c);
break;
@@ -239,25 +213,20 @@ void PublishAvahi::client_callback(AvahiClient *c, AvahiClientState state, AVAHI
logE << "Client failure: " << avahi_strerror(avahi_client_errno(c)) << "\n";
avahi_simple_poll_quit(simple_poll);
-
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. */
+ /// 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. */
+ /// 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:
diff --git a/server/publishAvahi.h b/server/publishZeroConf/publishAvahi.h
similarity index 97%
rename from server/publishAvahi.h
rename to server/publishZeroConf/publishAvahi.h
index 7f105800..80e0f536 100644
--- a/server/publishAvahi.h
+++ b/server/publishZeroConf/publishAvahi.h
@@ -52,7 +52,7 @@ private:
AvahiClient* client_;
std::thread pollThread_;
std::atomic active_;
- std::vector services;
+ std::vector services_;
};
diff --git a/server/publishBonjour.cpp b/server/publishZeroConf/publishBonjour.cpp
similarity index 94%
rename from server/publishBonjour.cpp
rename to server/publishZeroConf/publishBonjour.cpp
index 1bc78cb6..da80ca6c 100644
--- a/server/publishBonjour.cpp
+++ b/server/publishZeroConf/publishBonjour.cpp
@@ -146,6 +146,7 @@ void PublishBonjour::publish(const std::vector& services)
DNSServiceFlags flags = 0;
Opaque16 registerPort = { { static_cast(service.port_ >> 8), static_cast(service.port_ & 0xFF) } };
DNSServiceRef client = NULL;
+// DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, service.txt_.size(), service.txt_.empty()?NULL:service.txt_.c_str(), reg_reply, this);
DNSServiceRegister(&client, flags, kDNSServiceInterfaceIndexAny, serviceName_.c_str(), service.name_.c_str(), NULL, NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, this);
clients.push_back(client);
}
@@ -156,5 +157,3 @@ void PublishBonjour::publish(const std::vector& services)
-
-
diff --git a/server/publishBonjour.h b/server/publishZeroConf/publishBonjour.h
similarity index 100%
rename from server/publishBonjour.h
rename to server/publishZeroConf/publishBonjour.h
diff --git a/server/publishmDNS.h b/server/publishZeroConf/publishmDNS.h
similarity index 100%
rename from server/publishmDNS.h
rename to server/publishZeroConf/publishmDNS.h
diff --git a/server/snapServer.cpp b/server/snapServer.cpp
index c35cc36f..88d780af 100644
--- a/server/snapServer.cpp
+++ b/server/snapServer.cpp
@@ -30,7 +30,7 @@
#include "encoder/encoderFactory.h"
#include "streamServer.h"
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
-#include "publishmDNS.h"
+#include "publishZeroConf/publishmDNS.h"
#endif
#include "config.h"
#include "common/log.h"
From e91eb74f3e09db8f1f9d8b56d6fdcb0246f21a06 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Wed, 19 Oct 2016 09:22:37 +0200
Subject: [PATCH 12/24] more accurate getTickCount for macOS
---
common/timeDefs.h | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/common/timeDefs.h b/common/timeDefs.h
index 48ad2234..847ad809 100644
--- a/common/timeDefs.h
+++ b/common/timeDefs.h
@@ -21,6 +21,10 @@
#include
#include
+#ifdef MACOS
+#include
+#include
+#endif
namespace chronos
{
@@ -49,9 +53,12 @@ namespace chronos
inline static long getTickCount()
{
#ifdef MACOS
- struct timeval now;
- gettimeofday(&now, NULL);
- return now.tv_sec*1000 + now.tv_usec / 1000;
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+ return mts.tv_sec*1000 + mts.tv_nsec / 1000000;
#else
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
From ad5af4bd8ab7311a1e28fc8d92bd75b8a0830f36 Mon Sep 17 00:00:00 2001
From: badaix
Date: Wed, 19 Oct 2016 09:27:40 +0200
Subject: [PATCH 13/24] fixed typo
---
server/publishZeroConf/publishAvahi.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/server/publishZeroConf/publishAvahi.cpp b/server/publishZeroConf/publishAvahi.cpp
index f1f655ca..acbfc71d 100644
--- a/server/publishZeroConf/publishAvahi.cpp
+++ b/server/publishZeroConf/publishAvahi.cpp
@@ -128,10 +128,9 @@ void PublishAvahi::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState
void PublishAvahi::create_services(AvahiClient *c)
{
- char *n, r[128];
- int ret;
assert(c);
-
+ char *n;
+
/// If this is the first time we're called, let's create a new entry group if necessary
if (!group)
{
@@ -143,12 +142,13 @@ void PublishAvahi::create_services(AvahiClient *c)
}
/// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
+ int ret;
if (avahi_entry_group_is_empty(group))
{
logO << "Adding service '" << name << "'\n";
/// We will now add two services and one subtype to the entry group
- for (const auto& service: services)
+ for (const auto& service: services_)
{
if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, service.name_.c_str(), NULL, NULL, service.port_, NULL)) < 0)
{
From e8bf669aba1bb6b517d94c7a2f06de63a4aec5d1 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Wed, 19 Oct 2016 10:59:41 +0200
Subject: [PATCH 14/24] install/uninstall for macOS
---
client/Makefile | 22 ++++++++++++++++++++++
client/debian/snapclient.plist | 17 +++++++++++++++++
server/Makefile | 18 ++++++++++++++++++
server/debian/snapserver.plist | 17 +++++++++++++++++
4 files changed, 74 insertions(+)
create mode 100644 client/debian/snapclient.plist
create mode 100644 server/debian/snapserver.plist
diff --git a/client/Makefile b/client/Makefile
index 10911397..b7181ab9 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -78,6 +78,15 @@ install:
install -D -g root -o root $(BIN) $(TARGET_DIR)/sbin/$(BIN)
install -D -g root -o root $(BIN).1 $(TARGET_DIR)/share/man/man1/$(BIN).1
+else ifeq ($(TARGET), MACOS)
+
+install:
+ echo macOS
+ install -g wheel -o root $(BIN) $(TARGET_DIR)/local/bin/$(BIN)
+ install -g wheel -o root $(BIN).1 $(TARGET_DIR)/local/share/man/man1/$(BIN).1
+ install -g wheel -o root debian/$(BIN).plist /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist
+ launchctl load /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist
+
else
install:
@@ -111,6 +120,17 @@ installsysv:
/etc/init.d/$(BIN) start; \
+ifeq ($(TARGET), MACOS)
+
+uninstall:
+ @launchctl unload /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist; \
+ killall -9 $(BIN); \
+ rm -f $(TARGET_DIR)/local/bin/$(BIN); \
+ rm -f $(TARGET_DIR)/local/share/man/man1/$(BIN).1; \
+ rm -f /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist; \
+
+else
+
uninstall:
rm -f $(TARGET_DIR)/share/man/man1/$(BIN).1
@if [[ `systemctl` =~ -\.mount ]]; then \
@@ -123,6 +143,8 @@ uninstall:
echo cannot tell; \
fi; \
+endif
+
uninstallsysv:
@/etc/init.d/$(BIN) stop; \
killall -9 $(BIN); \
diff --git a/client/debian/snapclient.plist b/client/debian/snapclient.plist
new file mode 100644
index 00000000..2a89be67
--- /dev/null
+++ b/client/debian/snapclient.plist
@@ -0,0 +1,17 @@
+
+
+
+
+ Label
+ Snapclient
+ ProgramArguments
+
+ /usr/local/bin/snapclient
+ -d
+
+ RunAtLoad
+
+ KeepAlive
+
+
+
diff --git a/server/Makefile b/server/Makefile
index f9d55e8c..bf514b9d 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -84,6 +84,15 @@ install:
install -g wheel -o root -m 555 $(BIN).1 $(TARGET_DIR)/local/man/man1/$(BIN).1
install -g wheel -o root -m 555 debian/$(BIN).bsd $(TARGET_DIR)/local/etc/rc.d/$(BIN)
+else ifeq ($(TARGET), MACOS)
+
+install:
+ echo macOS
+ install -g wheel -o root $(BIN) $(TARGET_DIR)/local/bin/$(BIN)
+ install -g wheel -o root $(BIN).1 $(TARGET_DIR)/local/share/man/man1/$(BIN).1
+ install -g wheel -o root debian/$(BIN).plist /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist
+ launchctl load /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist
+
else
install:
@@ -130,6 +139,15 @@ uninstall:
rm -f $(TARGET_DIR)/local/man/man1/$(BIN).1; \
rm -f $(TARGET_DIR)/local/etc/rc.d/$(BIN); \
+else ifeq ($(TARGET), MACOS)
+
+uninstall:
+ @launchctl unload /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist; \
+ killall -9 $(BIN); \
+ rm -f $(TARGET_DIR)/local/bin/$(BIN); \
+ rm -f $(TARGET_DIR)/local/share/man/man1/$(BIN).1; \
+ rm -f /Library/LaunchAgents/de.badaix.snapcast.$(BIN).plist; \
+
else
uninstall:
diff --git a/server/debian/snapserver.plist b/server/debian/snapserver.plist
new file mode 100644
index 00000000..5cdac7be
--- /dev/null
+++ b/server/debian/snapserver.plist
@@ -0,0 +1,17 @@
+
+
+
+
+ Label
+ Snapserver
+ ProgramArguments
+
+ /usr/local/bin/snapserver
+ -d
+
+ RunAtLoad
+
+ KeepAlive
+
+
+
From aaee61bf2eecc967656910e98216edd2f99dcca5 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Wed, 19 Oct 2016 11:03:40 +0200
Subject: [PATCH 15/24] changed plist label
---
client/debian/snapclient.plist | 26 +++++++++++++-------------
server/debian/snapserver.plist | 26 +++++++++++++-------------
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/client/debian/snapclient.plist b/client/debian/snapclient.plist
index 2a89be67..81bff5ce 100644
--- a/client/debian/snapclient.plist
+++ b/client/debian/snapclient.plist
@@ -1,17 +1,17 @@
-
- Label
- Snapclient
- ProgramArguments
-
- /usr/local/bin/snapclient
- -d
-
- RunAtLoad
-
- KeepAlive
-
-
+
+ Label
+ de.badaix.snapcast.snapclient
+ ProgramArguments
+
+ /usr/local/bin/snapclient
+ -d
+
+ RunAtLoad
+
+ KeepAlive
+
+
diff --git a/server/debian/snapserver.plist b/server/debian/snapserver.plist
index 5cdac7be..e06cf183 100644
--- a/server/debian/snapserver.plist
+++ b/server/debian/snapserver.plist
@@ -1,17 +1,17 @@
-
- Label
- Snapserver
- ProgramArguments
-
- /usr/local/bin/snapserver
- -d
-
- RunAtLoad
-
- KeepAlive
-
-
+
+ Label
+ de.badaix.snapcast.snapserver
+ ProgramArguments
+
+ /usr/local/bin/snapserver
+ -d
+
+ RunAtLoad
+
+ KeepAlive
+
+
From d9ee0c1f520dca4e51a3a8e46e084344029bd021 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Thu, 20 Oct 2016 11:00:24 +0200
Subject: [PATCH 16/24] reformatted code
---
client/player/coreAudioPlayer.cpp | 105 ++++++++++++------------
client/player/coreAudioPlayer.h | 2 +-
server/encoder/oggEncoder.cpp | 74 ++++++++---------
server/encoder/oggEncoder.h | 18 ++--
server/publishZeroConf/publishAvahi.cpp | 2 +-
5 files changed, 100 insertions(+), 101 deletions(-)
diff --git a/client/player/coreAudioPlayer.cpp b/client/player/coreAudioPlayer.cpp
index a61ca553..e70e5385 100644
--- a/client/player/coreAudioPlayer.cpp
+++ b/client/player/coreAudioPlayer.cpp
@@ -47,18 +47,19 @@ CoreAudioPlayer::~CoreAudioPlayer()
void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bufferRef)
{
- /// Estimate the playout delay by checking the number of frames left in the buffer
- /// and add ms_ (= complete buffer size). Based on trying.
- AudioTimeStamp timestamp;
- AudioQueueGetCurrentTime(queue, timeLine, ×tamp, NULL);
- size_t bufferedFrames = (frames_ - ((uint64_t)timestamp.mSampleTime % frames_)) % frames_;
- size_t bufferedMs = bufferedFrames * 1000 / pubStream_->getFormat().rate + (ms_ * (NUM_BUFFERS - 1));
- /// 15ms DAC delay. Based on trying.
- bufferedMs += 15;
+ /// Estimate the playout delay by checking the number of frames left in the buffer
+ /// and add ms_ (= complete buffer size). Based on trying.
+ AudioTimeStamp timestamp;
+ AudioQueueGetCurrentTime(queue, timeLine_, ×tamp, NULL);
+ size_t bufferedFrames = (frames_ - ((uint64_t)timestamp.mSampleTime % frames_)) % frames_;
+ size_t bufferedMs = bufferedFrames * 1000 / pubStream_->getFormat().rate + (ms_ * (NUM_BUFFERS - 1));
+ /// 15ms DAC delay. Based on trying.
+ bufferedMs += 15;
// logO << "buffered: " << bufferedFrames << ", ms: " << bufferedMs << ", mSampleTime: " << timestamp.mSampleTime << "\n";
+ /// TODO: sometimes this bufferedMS or AudioTimeStamp wraps around 1s (i.e. we're 1s out of sync (behind)) and recovers later on
chronos::usec delay(bufferedMs * 1000);
- char *buffer = (char*)bufferRef->mAudioData;
+ char *buffer = (char*)bufferRef->mAudioData;
if (!pubStream_->getPlayerChunk(buffer, delay, frames_))
{
logO << "Failed to get chunk. Playing silence.\n";
@@ -70,60 +71,60 @@ void CoreAudioPlayer::playerCallback(AudioQueueRef queue, AudioQueueBufferRef bu
}
// OSStatus status =
- AudioQueueEnqueueBuffer(queue, bufferRef, 0, NULL);
+ AudioQueueEnqueueBuffer(queue, bufferRef, 0, NULL);
- if (!active_)
- {
- AudioQueueStop(queue, false);
- AudioQueueDispose(queue, false);
- CFRunLoopStop(CFRunLoopGetCurrent());
- }
+ if (!active_)
+ {
+ AudioQueueStop(queue, false);
+ AudioQueueDispose(queue, false);
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ }
}
void CoreAudioPlayer::worker()
{
- const SampleFormat& sampleFormat = pubStream_->getFormat();
+ const SampleFormat& sampleFormat = pubStream_->getFormat();
- AudioStreamBasicDescription format;
- format.mSampleRate = sampleFormat.rate;
- format.mFormatID = kAudioFormatLinearPCM;
- format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;// | kAudioFormatFlagIsPacked;
- format.mBitsPerChannel = sampleFormat.bits;
- format.mChannelsPerFrame = sampleFormat.channels;
- format.mBytesPerFrame = sampleFormat.frameSize;
- format.mFramesPerPacket = 1;
- format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
- format.mReserved = 0;
+ AudioStreamBasicDescription format;
+ format.mSampleRate = sampleFormat.rate;
+ format.mFormatID = kAudioFormatLinearPCM;
+ format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;// | kAudioFormatFlagIsPacked;
+ format.mBitsPerChannel = sampleFormat.bits;
+ format.mChannelsPerFrame = sampleFormat.channels;
+ format.mBytesPerFrame = sampleFormat.frameSize;
+ format.mFramesPerPacket = 1;
+ format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
+ format.mReserved = 0;
- AudioQueueRef queue;
- AudioQueueNewOutput(&format, callback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &queue);
- AudioQueueCreateTimeline(queue, &timeLine);
-
- // Apple recommends this as buffer size:
- // https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html
- // static const int maxBufferSize = 0x10000; // limit maximum size to 64K
- // static const int minBufferSize = 0x4000; // limit minimum size to 16K
- //
- // For 100ms @ 48000:16:2 we have 19.2K
- // frames: 4800, ms: 100, buffer size: 19200
+ AudioQueueRef queue;
+ AudioQueueNewOutput(&format, callback, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &queue);
+ AudioQueueCreateTimeline(queue, &timeLine_);
+
+ // Apple recommends this as buffer size:
+ // https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/CoreAudioEssentials/CoreAudioEssentials.html
+ // static const int maxBufferSize = 0x10000; // limit maximum size to 64K
+ // static const int minBufferSize = 0x4000; // limit minimum size to 16K
+ //
+ // For 100ms @ 48000:16:2 we have 19.2K
+ // frames: 4800, ms: 100, buffer size: 19200
frames_ = (sampleFormat.rate * ms_) / 1000;
- ms_ = frames_ * 1000 / sampleFormat.rate;
+ ms_ = frames_ * 1000 / sampleFormat.rate;
buff_size_ = frames_ * sampleFormat.frameSize;
- logO << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n";
-
- AudioQueueBufferRef buffers[NUM_BUFFERS];
- for (int i = 0; i < NUM_BUFFERS; i++)
- {
- AudioQueueAllocateBuffer(queue, buff_size_, &buffers[i]);
- buffers[i]->mAudioDataByteSize = buff_size_;
- callback(this, queue, buffers[i]);
- }
+ logO << "frames: " << frames_ << ", ms: " << ms_ << ", buffer size: " << buff_size_ << "\n";
+
+ AudioQueueBufferRef buffers[NUM_BUFFERS];
+ for (int i = 0; i < NUM_BUFFERS; i++)
+ {
+ AudioQueueAllocateBuffer(queue, buff_size_, &buffers[i]);
+ buffers[i]->mAudioDataByteSize = buff_size_;
+ callback(this, queue, buffers[i]);
+ }
- logE << "CoreAudioPlayer::worker\n";
- AudioQueueCreateTimeline(queue, &timeLine);
- AudioQueueStart(queue, NULL);
- CFRunLoopRun();
+ logE << "CoreAudioPlayer::worker\n";
+ AudioQueueCreateTimeline(queue, &timeLine_);
+ AudioQueueStart(queue, NULL);
+ CFRunLoopRun();
}
diff --git a/client/player/coreAudioPlayer.h b/client/player/coreAudioPlayer.h
index 014bc7fa..8098b874 100644
--- a/client/player/coreAudioPlayer.h
+++ b/client/player/coreAudioPlayer.h
@@ -45,7 +45,7 @@ public:
protected:
virtual void worker();
- AudioQueueTimelineRef timeLine;
+ AudioQueueTimelineRef timeLine_;
size_t ms_;
size_t frames_;
size_t buff_size_;
diff --git a/server/encoder/oggEncoder.cpp b/server/encoder/oggEncoder.cpp
index 229f9080..fd69405a 100644
--- a/server/encoder/oggEncoder.cpp
+++ b/server/encoder/oggEncoder.cpp
@@ -28,7 +28,7 @@
using namespace std;
-OggEncoder::OggEncoder(const std::string& codecOptions) : Encoder(codecOptions), lastGranulepos(0)
+OggEncoder::OggEncoder(const std::string& codecOptions) : Encoder(codecOptions), lastGranulepos_(0)
{
}
@@ -56,7 +56,7 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
double res = 0;
logD << "payload: " << chunk->payloadSize << "\tframes: " << chunk->getFrameCount() << "\tduration: " << chunk->duration().count() << "\n";
int frames = chunk->getFrameCount();
- float **buffer=vorbis_analysis_buffer(&vd, frames);
+ float **buffer=vorbis_analysis_buffer(&vd_, frames);
/* uninterleave samples */
for (size_t channel = 0; channel < sampleFormat_.channels; ++channel)
@@ -82,7 +82,7 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
}
/* tell the library how much we actually submitted */
- vorbis_analysis_wrote(&vd, frames);
+ vorbis_analysis_wrote(&vd_, frames);
msg::PcmChunk* oggChunk = new msg::PcmChunk(chunk->format, 0);
@@ -90,36 +90,36 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
more involved (potentially parallel) processing. Get a single
block for encoding now */
size_t pos = 0;
- while (vorbis_analysis_blockout(&vd, &vb)==1)
+ while (vorbis_analysis_blockout(&vd_, &vb_)==1)
{
/* analysis, assume we want to use bitrate management */
- vorbis_analysis(&vb, NULL);
- vorbis_bitrate_addblock(&vb);
+ vorbis_analysis(&vb_, NULL);
+ vorbis_bitrate_addblock(&vb_);
- while (vorbis_bitrate_flushpacket(&vd, &op))
+ while (vorbis_bitrate_flushpacket(&vd_, &op_))
{
/* weld the packet into the bitstream */
- ogg_stream_packetin(&os, &op);
+ ogg_stream_packetin(&os_, &op_);
/* write out pages (if any) */
while (true)
{
- int result = ogg_stream_flush(&os, &og);
+ int result = ogg_stream_flush(&os_, &og_);
if (result == 0)
break;
- res = os.granulepos - lastGranulepos;
+ res = os_.granulepos - lastGranulepos_;
- size_t nextLen = pos + og.header_len + og.body_len;
+ size_t nextLen = pos + og_.header_len + og_.body_len;
// make chunk larger
if (oggChunk->payloadSize < nextLen)
oggChunk->payload = (char*)realloc(oggChunk->payload, nextLen);
- memcpy(oggChunk->payload + pos, og.header, og.header_len);
- pos += og.header_len;
- memcpy(oggChunk->payload + pos, og.body, og.body_len);
- pos += og.body_len;
+ memcpy(oggChunk->payload + pos, og_.header, og_.header_len);
+ pos += og_.header_len;
+ memcpy(oggChunk->payload + pos, og_.body, og_.body_len);
+ pos += og_.body_len;
- if (ogg_page_eos(&og))
+ if (ogg_page_eos(&og_))
break;
}
}
@@ -129,7 +129,7 @@ void OggEncoder::encode(const msg::PcmChunk* chunk)
{
res /= (sampleFormat_.rate / 1000.);
// logO << "res: " << res << "\n";
- lastGranulepos = os.granulepos;
+ lastGranulepos_ = os_.granulepos;
// make oggChunk smaller
oggChunk->payload = (char*)realloc(oggChunk->payload, pos);
oggChunk->payloadSize = pos;
@@ -164,7 +164,7 @@ void OggEncoder::initEncoder()
}
/********** Encode setup ************/
- vorbis_info_init(&vi);
+ vorbis_info_init(&vi_);
/* choose an encoding mode. A few possibilities commented out, one
actually used: */
@@ -195,7 +195,7 @@ void OggEncoder::initEncoder()
*********************************************************************/
- int ret = vorbis_encode_init_vbr(&vi, sampleFormat_.channels, sampleFormat_.rate, quality);
+ int ret = vorbis_encode_init_vbr(&vi_, sampleFormat_.channels, sampleFormat_.rate, quality);
/* do not continue if setup failed; this can happen if we ask for a
mode that libVorbis does not support (eg, too low a bitrate, etc,
@@ -205,20 +205,20 @@ void OggEncoder::initEncoder()
throw SnapException("failed to init encoder");
/* add a comment */
- vorbis_comment_init(&vc);
- vorbis_comment_add_tag(&vc, "TITLE", "SnapStream");
- vorbis_comment_add_tag(&vc, "VERSION", VERSION);
- vorbis_comment_add_tag(&vc, "SAMPLE_FORMAT", sampleFormat_.getFormat().c_str());
+ vorbis_comment_init(&vc_);
+ vorbis_comment_add_tag(&vc_, "TITLE", "SnapStream");
+ vorbis_comment_add_tag(&vc_, "VERSION", VERSION);
+ vorbis_comment_add_tag(&vc_, "SAMPLE_FORMAT", sampleFormat_.getFormat().c_str());
/* set up the analysis state and auxiliary encoding storage */
- vorbis_analysis_init(&vd, &vi);
- vorbis_block_init(&vd, &vb);
+ vorbis_analysis_init(&vd_, &vi_);
+ vorbis_block_init(&vd_, &vb_);
/* set up our packet->stream encoder */
/* pick a random serial number; that way we can more likely build
chained streams just by concatenation */
srand(time(NULL));
- ogg_stream_init(&os, rand());
+ ogg_stream_init(&os_, rand());
/* Vorbis streams begin with three headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg
@@ -231,10 +231,10 @@ void OggEncoder::initEncoder()
ogg_packet header_comm;
ogg_packet header_code;
- vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code);
- ogg_stream_packetin(&os, &header);
- ogg_stream_packetin(&os, &header_comm);
- ogg_stream_packetin(&os, &header_code);
+ vorbis_analysis_headerout(&vd_, &vc_, &header, &header_comm, &header_code);
+ ogg_stream_packetin(&os_, &header);
+ ogg_stream_packetin(&os_, &header_comm);
+ ogg_stream_packetin(&os_, &header_code);
/* This ensures the actual
* audio data will start on a new page, as per spec
@@ -243,16 +243,16 @@ void OggEncoder::initEncoder()
headerChunk_.reset(new msg::CodecHeader("ogg"));
while (true)
{
- int result = ogg_stream_flush(&os, &og);
+ int result = ogg_stream_flush(&os_, &og_);
if (result == 0)
break;
- headerChunk_->payloadSize += og.header_len + og.body_len;
+ headerChunk_->payloadSize += og_.header_len + og_.body_len;
headerChunk_->payload = (char*)realloc(headerChunk_->payload, headerChunk_->payloadSize);
- logD << "HeadLen: " << og.header_len << ", bodyLen: " << og.body_len << ", result: " << result << "\n";
- memcpy(headerChunk_->payload + pos, og.header, og.header_len);
- pos += og.header_len;
- memcpy(headerChunk_->payload + pos, og.body, og.body_len);
- pos += og.body_len;
+ logD << "HeadLen: " << og_.header_len << ", bodyLen: " << og_.body_len << ", result: " << result << "\n";
+ memcpy(headerChunk_->payload + pos, og_.header, og_.header_len);
+ pos += og_.header_len;
+ memcpy(headerChunk_->payload + pos, og_.body, og_.body_len);
+ pos += og_.body_len;
}
}
diff --git a/server/encoder/oggEncoder.h b/server/encoder/oggEncoder.h
index 19393f62..8c8412f4 100644
--- a/server/encoder/oggEncoder.h
+++ b/server/encoder/oggEncoder.h
@@ -35,19 +35,17 @@ protected:
virtual void initEncoder();
private:
- ogg_stream_state os; /* take physical pages, weld into a logical
- stream of packets */
- ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
- ogg_packet op; /* one raw packet of data for decode */
+ ogg_stream_state os_; /// take physical pages, weld into a logical stream of packets
+ ogg_page og_; /// one Ogg bitstream page. Vorbis packets are inside
+ ogg_packet op_; /// one raw packet of data for decode
- vorbis_info vi; /* struct that stores all the static vorbis bitstream
- settings */
- vorbis_comment vc; /* struct that stores all the user comments */
+ vorbis_info vi_; /// struct that stores all the static vorbis bitstream settings
+ vorbis_comment vc_; /// struct that stores all the user comments
- vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
- vorbis_block vb; /* local working space for packet->PCM decode */
+ vorbis_dsp_state vd_; /// central working state for the packet->PCM decoder
+ vorbis_block vb_; /// local working space for packet->PCM decode
- ogg_int64_t lastGranulepos;
+ ogg_int64_t lastGranulepos_;
};
diff --git a/server/publishZeroConf/publishAvahi.cpp b/server/publishZeroConf/publishAvahi.cpp
index acbfc71d..f6a75193 100644
--- a/server/publishZeroConf/publishAvahi.cpp
+++ b/server/publishZeroConf/publishAvahi.cpp
@@ -161,7 +161,7 @@ void PublishAvahi::create_services(AvahiClient *c)
}
/// Add an additional (hypothetic) subtype
-/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0))
+/* if ((ret = avahi_entry_group_add_service_subtype(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), name, "_printer._tcp", NULL, "_magic._sub._printer._tcp") < 0))
{
fprintf(stderr, "Failed to add subtype _magic._sub._printer._tcp: %s\n", avahi_strerror(ret));
goto fail;
From daf5d52b7b2fdf482dfd5c75ff75fe3ba434a09d Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Thu, 20 Oct 2016 12:06:02 +0200
Subject: [PATCH 17/24] updated popl license
---
.../Snapcast/src/main/assets/files/about.html | 1316 +++++++----------
1 file changed, 564 insertions(+), 752 deletions(-)
diff --git a/android/Snapcast/src/main/assets/files/about.html b/android/Snapcast/src/main/assets/files/about.html
index 6766f69f..a0dcc6e9 100644
--- a/android/Snapcast/src/main/assets/files/about.html
+++ b/android/Snapcast/src/main/assets/files/about.html
@@ -1,763 +1,575 @@
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
- Snapcast licenses
-
+ Snapcast licenses
+
-
-
-Snapcast
-
-Copyright © 2014 - 2016 BadAix
-Author: Johannes Pohl and contributors
-
-
-
License
-
-
Snapcast is licensed under the GNU General Public License, version 3 or
- later (herein referred to as GPL).
-
-
How Can I Help?
-
-
If you find Snapcast useful, then I'd really appreciate it if you'd consider contributing to
- the project however you can. Donating is the easiest.
-
-
You can donate Bitcoins here: 1Cm9WL99fyYSPbLvgnGbRihjb1GYZ5aZFz
-
-
-
-
Sources
-
-
The sources to this application can be retrieved at https://github.com/badaix/snapcast.
-
-
Libraries
-
-
Snapcast uses external libraries that make extensive use of the following persons' or
- companies' code:
-
-
-
-Back to the top
-
-
-
-
-
-
-
-
GNU GENERAL PUBLIC LICENSE
-
-
Version 3, 29 June 2007
-
-
Copyright © 2007 Free Software Foundation, Inc.
- <http://fsf.org/>
-
-
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
Preamble
-
-
The GNU General Public License is a free, copyleft license for
- software and other kinds of works.
-
-
The licenses for most software and other practical works are designed
- to take away your freedom to share and change the works. By contrast,
- the GNU General Public License is intended to guarantee your freedom to
- share and change all versions of a program--to make sure it remains free
- software for all its users. We, the Free Software Foundation, use the
- GNU General Public License for most of our software; it applies also to
- any other work released this way by its authors. You can apply it to
- your programs, too.
-
-
When we speak of free software, we are referring to freedom, not
- price. Our General Public Licenses are designed to make sure that you
- have the freedom to distribute copies of free software (and charge for
- them if you wish), that you receive source code or can get it if you
- want it, that you can change the software or use pieces of it in new
- free programs, and that you know you can do these things.
-
-
To protect your rights, we need to prevent others from denying you
- these rights or asking you to surrender the rights. Therefore, you have
- certain responsibilities if you distribute copies of the software, or if
- you modify it: responsibilities to respect the freedom of others.
-
-
For example, if you distribute copies of such a program, whether
- gratis or for a fee, you must pass on to the recipients the same
- freedoms that you received. You must make sure that they, too, receive
- or can get the source code. And you must show them these terms so they
- know their rights.
-
-
Developers that use the GNU GPL protect your rights with two steps:
- (1) assert copyright on the software, and (2) offer you this License
- giving you legal permission to copy, distribute and/or modify it.
-
-
For the developers' and authors' protection, the GPL clearly explains
- that there is no warranty for this free software. For both users' and
- authors' sake, the GPL requires that modified versions be marked as
- changed, so that their problems will not be attributed erroneously to
- authors of previous versions.
-
-
Some devices are designed to deny users access to install or run
- modified versions of the software inside them, although the manufacturer
- can do so. This is fundamentally incompatible with the aim of
- protecting users' freedom to change the software. The systematic
- pattern of such abuse occurs in the area of products for individuals to
- use, which is precisely where it is most unacceptable. Therefore, we
- have designed this version of the GPL to prohibit the practice for those
- products. If such problems arise substantially in other domains, we
- stand ready to extend this provision to those domains in future versions
- of the GPL, as needed to protect the freedom of users.
-
-
Finally, every program is threatened constantly by software patents.
- States should not allow patents to restrict development and use of
- software on general-purpose computers, but in those that do, we wish to
- avoid the special danger that patents applied to a free program could
- make it effectively proprietary. To prevent this, the GPL assures that
- patents cannot be used to render the program non-free.
-
-
The precise terms and conditions for copying, distribution and
- modification follow.
-
-
TERMS AND CONDITIONS
-
-
0. Definitions.
-
-
“This License” refers to version 3 of the GNU General Public License.
-
-
“Copyright” also means copyright-like laws that apply to other kinds of
- works, such as semiconductor masks.
-
-
“The Program” refers to any copyrightable work licensed under this
- License. Each licensee is addressed as “you”. “Licensees” and
- “recipients” may be individuals or organizations.
-
-
To “modify” a work means to copy from or adapt all or part of the work
- in a fashion requiring copyright permission, other than the making of an
- exact copy. The resulting work is called a “modified version” of the
- earlier work or a work “based on” the earlier work.
-
-
A “covered work” means either the unmodified Program or a work based
- on the Program.
-
-
To “propagate” a work means to do anything with it that, without
- permission, would make you directly or secondarily liable for
- infringement under applicable copyright law, except executing it on a
- computer or modifying a private copy. Propagation includes copying,
- distribution (with or without modification), making available to the
- public, and in some countries other activities as well.
-
-
To “convey” a work means any kind of propagation that enables other
- parties to make or receive copies. Mere interaction with a user through
- a computer network, with no transfer of a copy, is not conveying.
-
-
An interactive user interface displays “Appropriate Legal Notices”
- to the extent that it includes a convenient and prominently visible
- feature that (1) displays an appropriate copyright notice, and (2)
- tells the user that there is no warranty for the work (except to the
- extent that warranties are provided), that licensees may convey the
- work under this License, and how to view a copy of this License. If
- the interface presents a list of user commands or options, such as a
- menu, a prominent item in the list meets this criterion.
-
-
1. Source Code.
-
-
The “source code” for a work means the preferred form of the work
- for making modifications to it. “Object code” means any non-source
- form of a work.
-
-
A “Standard Interface” means an interface that either is an official
- standard defined by a recognized standards body, or, in the case of
- interfaces specified for a particular programming language, one that
- is widely used among developers working in that language.
-
-
The “System Libraries” of an executable work include anything, other
- than the work as a whole, that (a) is included in the normal form of
- packaging a Major Component, but which is not part of that Major
- Component, and (b) serves only to enable use of the work with that
- Major Component, or to implement a Standard Interface for which an
- implementation is available to the public in source code form. A
- “Major Component”, in this context, means a major essential component
- (kernel, window system, and so on) of the specific operating system
- (if any) on which the executable work runs, or a compiler used to
- produce the work, or an object code interpreter used to run it.
-
-
The “Corresponding Source” for a work in object code form means all
- the source code needed to generate, install, and (for an executable
- work) run the object code and to modify the work, including scripts to
- control those activities. However, it does not include the work's
- System Libraries, or general-purpose tools or generally available free
- programs which are used unmodified in performing those activities but
- which are not part of the work. For example, Corresponding Source
- includes interface definition files associated with source files for
- the work, and the source code for shared libraries and dynamically
- linked subprograms that the work is specifically designed to require,
- such as by intimate data communication or control flow between those
- subprograms and other parts of the work.
-
-
The Corresponding Source need not include anything that users
- can regenerate automatically from other parts of the Corresponding
- Source.
-
-
The Corresponding Source for a work in source code form is that
- same work.
-
-
2. Basic Permissions.
-
-
All rights granted under this License are granted for the term of
- copyright on the Program, and are irrevocable provided the stated
- conditions are met. This License explicitly affirms your unlimited
- permission to run the unmodified Program. The output from running a
- covered work is covered by this License only if the output, given its
- content, constitutes a covered work. This License acknowledges your
- rights of fair use or other equivalent, as provided by copyright law.
-
-
You may make, run and propagate covered works that you do not
- convey, without conditions so long as your license otherwise remains
- in force. You may convey covered works to others for the sole purpose
- of having them make modifications exclusively for you, or provide you
- with facilities for running those works, provided that you comply with
- the terms of this License in conveying all material for which you do
- not control copyright. Those thus making or running the covered works
- for you must do so exclusively on your behalf, under your direction
- and control, on terms that prohibit them from making any copies of
- your copyrighted material outside their relationship with you.
-
-
Conveying under any other circumstances is permitted solely under
- the conditions stated below. Sublicensing is not allowed; section 10
- makes it unnecessary.
-
-
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-
No covered work shall be deemed part of an effective technological
- measure under any applicable law fulfilling obligations under article
- 11 of the WIPO copyright treaty adopted on 20 December 1996, or
- similar laws prohibiting or restricting circumvention of such
- measures.
-
-
When you convey a covered work, you waive any legal power to forbid
- circumvention of technological measures to the extent such circumvention
- is effected by exercising rights under this License with respect to
- the covered work, and you disclaim any intention to limit operation or
- modification of the work as a means of enforcing, against the work's
- users, your or third parties' legal rights to forbid circumvention of
- technological measures.
-
-
4. Conveying Verbatim Copies.
-
-
You may convey verbatim copies of the Program's source code as you
- receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy an appropriate copyright notice;
- keep intact all notices stating that this License and any
- non-permissive terms added in accord with section 7 apply to the code;
- keep intact all notices of the absence of any warranty; and give all
- recipients a copy of this License along with the Program.
-
-
You may charge any price or no price for each copy that you convey,
- and you may offer support or warranty protection for a fee.
-
-
5. Conveying Modified Source Versions.
-
-
You may convey a work based on the Program, or the modifications to
- produce it from the Program, in the form of source code under the
- terms of section 4, provided that you also meet all of these conditions:
-
-
- - a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
-
- - b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- “keep intact all notices”.
-
-
- - c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
-
- - d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
-
-
-
A compilation of a covered work with other separate and independent
- works, which are not by their nature extensions of the covered work,
- and which are not combined with it such as to form a larger program,
- in or on a volume of a storage or distribution medium, is called an
- “aggregate” if the compilation and its resulting copyright are not
- used to limit the access or legal rights of the compilation's users
- beyond what the individual works permit. Inclusion of a covered work
- in an aggregate does not cause this License to apply to the other
- parts of the aggregate.
-
-
6. Conveying Non-Source Forms.
-
-
You may convey a covered work in object code form under the terms
- of sections 4 and 5, provided that you also convey the
- machine-readable Corresponding Source under the terms of this License,
- in one of these ways:
-
-
- - a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
-
- - b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
-
- - c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
-
- - d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
-
- - e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
-
-
-
A separable portion of the object code, whose source code is excluded
- from the Corresponding Source as a System Library, need not be
- included in conveying the object code work.
-
-
A “User Product” is either (1) a “consumer product”, which means any
- tangible personal property which is normally used for personal, family,
- or household purposes, or (2) anything designed or sold for incorporation
- into a dwelling. In determining whether a product is a consumer product,
- doubtful cases shall be resolved in favor of coverage. For a particular
- product received by a particular user, “normally used” refers to a
- typical or common use of that class of product, regardless of the status
- of the particular user or of the way in which the particular user
- actually uses, or expects or is expected to use, the product. A product
- is a consumer product regardless of whether the product has substantial
- commercial, industrial or non-consumer uses, unless such uses represent
- the only significant mode of use of the product.
-
-
“Installation Information” for a User Product means any methods,
- procedures, authorization keys, or other information required to install
- and execute modified versions of a covered work in that User Product from
- a modified version of its Corresponding Source. The information must
- suffice to ensure that the continued functioning of the modified object
- code is in no case prevented or interfered with solely because
- modification has been made.
-
-
If you convey an object code work under this section in, or with, or
- specifically for use in, a User Product, and the conveying occurs as
- part of a transaction in which the right of possession and use of the
- User Product is transferred to the recipient in perpetuity or for a
- fixed term (regardless of how the transaction is characterized), the
- Corresponding Source conveyed under this section must be accompanied
- by the Installation Information. But this requirement does not apply
- if neither you nor any third party retains the ability to install
- modified object code on the User Product (for example, the work has
- been installed in ROM).
-
-
The requirement to provide Installation Information does not include a
- requirement to continue to provide support service, warranty, or updates
- for a work that has been modified or installed by the recipient, or for
- the User Product in which it has been modified or installed. Access to a
- network may be denied when the modification itself materially and
- adversely affects the operation of the network or violates the rules and
- protocols for communication across the network.
-
-
Corresponding Source conveyed, and Installation Information provided,
- in accord with this section must be in a format that is publicly
- documented (and with an implementation available to the public in
- source code form), and must require no special password or key for
- unpacking, reading or copying.
-
-
7. Additional Terms.
-
-
“Additional permissions” are terms that supplement the terms of this
- License by making exceptions from one or more of its conditions.
- Additional permissions that are applicable to the entire Program shall
- be treated as though they were included in this License, to the extent
- that they are valid under applicable law. If additional permissions
- apply only to part of the Program, that part may be used separately
- under those permissions, but the entire Program remains governed by
- this License without regard to the additional permissions.
-
-
When you convey a copy of a covered work, you may at your option
- remove any additional permissions from that copy, or from any part of
- it. (Additional permissions may be written to require their own
- removal in certain cases when you modify the work.) You may place
- additional permissions on material, added by you to a covered work,
- for which you have or can give appropriate copyright permission.
-
-
Notwithstanding any other provision of this License, for material you
- add to a covered work, you may (if authorized by the copyright holders of
- that material) supplement the terms of this License with terms:
-
-
- - a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
-
- - b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
-
- - c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
-
- - d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
-
- - e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
-
- - f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
-
-
-
All other non-permissive additional terms are considered “further
- restrictions” within the meaning of section 10. If the Program as you
- received it, or any part of it, contains a notice stating that it is
- governed by this License along with a term that is a further
- restriction, you may remove that term. If a license document contains
- a further restriction but permits relicensing or conveying under this
- License, you may add to a covered work material governed by the terms
- of that license document, provided that the further restriction does
- not survive such relicensing or conveying.
-
-
If you add terms to a covered work in accord with this section, you
- must place, in the relevant source files, a statement of the
- additional terms that apply to those files, or a notice indicating
- where to find the applicable terms.
-
-
Additional terms, permissive or non-permissive, may be stated in the
- form of a separately written license, or stated as exceptions;
- the above requirements apply either way.
-
-
8. Termination.
-
-
You may not propagate or modify a covered work except as expressly
- provided under this License. Any attempt otherwise to propagate or
- modify it is void, and will automatically terminate your rights under
- this License (including any patent licenses granted under the third
- paragraph of section 11).
-
-
However, if you cease all violation of this License, then your
- license from a particular copyright holder is reinstated (a)
- provisionally, unless and until the copyright holder explicitly and
- finally terminates your license, and (b) permanently, if the copyright
- holder fails to notify you of the violation by some reasonable means
- prior to 60 days after the cessation.
-
-
Moreover, your license from a particular copyright holder is
- reinstated permanently if the copyright holder notifies you of the
- violation by some reasonable means, this is the first time you have
- received notice of violation of this License (for any work) from that
- copyright holder, and you cure the violation prior to 30 days after
- your receipt of the notice.
-
-
Termination of your rights under this section does not terminate the
- licenses of parties who have received copies or rights from you under
- this License. If your rights have been terminated and not permanently
- reinstated, you do not qualify to receive new licenses for the same
- material under section 10.
-
-
9. Acceptance Not Required for Having Copies.
-
-
You are not required to accept this License in order to receive or
- run a copy of the Program. Ancillary propagation of a covered work
- occurring solely as a consequence of using peer-to-peer transmission
- to receive a copy likewise does not require acceptance. However,
- nothing other than this License grants you permission to propagate or
- modify any covered work. These actions infringe copyright if you do
- not accept this License. Therefore, by modifying or propagating a
- covered work, you indicate your acceptance of this License to do so.
-
-
10. Automatic Licensing of Downstream Recipients.
-
-
Each time you convey a covered work, the recipient automatically
- receives a license from the original licensors, to run, modify and
- propagate that work, subject to this License. You are not responsible
- for enforcing compliance by third parties with this License.
-
-
An “entity transaction” is a transaction transferring control of an
- organization, or substantially all assets of one, or subdividing an
- organization, or merging organizations. If propagation of a covered
- work results from an entity transaction, each party to that
- transaction who receives a copy of the work also receives whatever
- licenses to the work the party's predecessor in interest had or could
- give under the previous paragraph, plus a right to possession of the
- Corresponding Source of the work from the predecessor in interest, if
- the predecessor has it or can get it with reasonable efforts.
-
-
You may not impose any further restrictions on the exercise of the
- rights granted or affirmed under this License. For example, you may
- not impose a license fee, royalty, or other charge for exercise of
- rights granted under this License, and you may not initiate litigation
- (including a cross-claim or counterclaim in a lawsuit) alleging that
- any patent claim is infringed by making, using, selling, offering for
- sale, or importing the Program or any portion of it.
-
-
11. Patents.
-
-
A “contributor” is a copyright holder who authorizes use under this
- License of the Program or a work on which the Program is based. The
- work thus licensed is called the contributor's “contributor version”.
-
-
A contributor's “essential patent claims” are all patent claims
- owned or controlled by the contributor, whether already acquired or
- hereafter acquired, that would be infringed by some manner, permitted
- by this License, of making, using, or selling its contributor version,
- but do not include claims that would be infringed only as a
- consequence of further modification of the contributor version. For
- purposes of this definition, “control” includes the right to grant
- patent sublicenses in a manner consistent with the requirements of
- this License.
-
-
Each contributor grants you a non-exclusive, worldwide, royalty-free
- patent license under the contributor's essential patent claims, to
- make, use, sell, offer for sale, import and otherwise run, modify and
- propagate the contents of its contributor version.
-
-
In the following three paragraphs, a “patent license” is any express
- agreement or commitment, however denominated, not to enforce a patent
- (such as an express permission to practice a patent or covenant not to
- sue for patent infringement). To “grant” such a patent license to a
- party means to make such an agreement or commitment not to enforce a
- patent against the party.
-
-
If you convey a covered work, knowingly relying on a patent license,
- and the Corresponding Source of the work is not available for anyone
- to copy, free of charge and under the terms of this License, through a
- publicly available network server or other readily accessible means,
- then you must either (1) cause the Corresponding Source to be so
- available, or (2) arrange to deprive yourself of the benefit of the
- patent license for this particular work, or (3) arrange, in a manner
- consistent with the requirements of this License, to extend the patent
- license to downstream recipients. “Knowingly relying” means you have
- actual knowledge that, but for the patent license, your conveying the
- covered work in a country, or your recipient's use of the covered work
- in a country, would infringe one or more identifiable patents in that
- country that you have reason to believe are valid.
-
-
If, pursuant to or in connection with a single transaction or
- arrangement, you convey, or propagate by procuring conveyance of, a
- covered work, and grant a patent license to some of the parties
- receiving the covered work authorizing them to use, propagate, modify
- or convey a specific copy of the covered work, then the patent license
- you grant is automatically extended to all recipients of the covered
- work and works based on it.
-
-
A patent license is “discriminatory” if it does not include within
- the scope of its coverage, prohibits the exercise of, or is
- conditioned on the non-exercise of one or more of the rights that are
- specifically granted under this License. You may not convey a covered
- work if you are a party to an arrangement with a third party that is
- in the business of distributing software, under which you make payment
- to the third party based on the extent of your activity of conveying
- the work, and under which the third party grants, to any of the
- parties who would receive the covered work from you, a discriminatory
- patent license (a) in connection with copies of the covered work
- conveyed by you (or copies made from those copies), or (b) primarily
- for and in connection with specific products or compilations that
- contain the covered work, unless you entered into that arrangement,
- or that patent license was granted, prior to 28 March 2007.
-
-
Nothing in this License shall be construed as excluding or limiting
- any implied license or other defenses to infringement that may
- otherwise be available to you under applicable patent law.
-
-
12. No Surrender of Others' Freedom.
-
-
If conditions are imposed on you (whether by court order, agreement or
- otherwise) that contradict the conditions of this License, they do not
- excuse you from the conditions of this License. If you cannot convey a
- covered work so as to satisfy simultaneously your obligations under this
- License and any other pertinent obligations, then as a consequence you may
- not convey it at all. For example, if you agree to terms that obligate you
- to collect a royalty for further conveying from those to whom you convey
- the Program, the only way you could satisfy both those terms and this
- License would be to refrain entirely from conveying the Program.
-
-
13. Use with the GNU Affero General Public License.
-
-
Notwithstanding any other provision of this License, you have
- permission to link or combine any covered work with a work licensed
- under version 3 of the GNU Affero General Public License into a single
- combined work, and to convey the resulting work. The terms of this
- License will continue to apply to the part which is the covered work,
- but the special requirements of the GNU Affero General Public License,
- section 13, concerning interaction through a network will apply to the
- combination as such.
-
-
14. Revised Versions of this License.
-
-
The Free Software Foundation may publish revised and/or new versions of
- the GNU General Public License from time to time. Such new versions will
- be similar in spirit to the present version, but may differ in detail to
- address new problems or concerns.
-
-
Each version is given a distinguishing version number. If the
- Program specifies that a certain numbered version of the GNU General
- Public License “or any later version” applies to it, you have the
- option of following the terms and conditions either of that numbered
- version or of any later version published by the Free Software
- Foundation. If the Program does not specify a version number of the
- GNU General Public License, you may choose any version ever published
- by the Free Software Foundation.
-
-
If the Program specifies that a proxy can decide which future
- versions of the GNU General Public License can be used, that proxy's
- public statement of acceptance of a version permanently authorizes you
- to choose that version for the Program.
-
-
Later license versions may give you additional or different
- permissions. However, no additional obligations are imposed on any
- author or copyright holder as a result of your choosing to follow a
- later version.
-
-
15. Disclaimer of Warranty.
-
-
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY
- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
- ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-
16. Limitation of Liability.
-
-
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
- THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
- GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
- USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
- DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
- PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
- EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGES.
-
-
17. Interpretation of Sections 15 and 16.
-
-
If the disclaimer of warranty and limitation of liability provided
- above cannot be given local legal effect according to their terms,
- reviewing courts shall apply local law that most closely approximates
- an absolute waiver of all civil liability in connection with the
- Program, unless a warranty or assumption of liability accompanies a
- copy of the Program in return for a fee.
-
-Back to the top
-
-Xiph.org BSD-like license
-
-Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
-
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of the Xiph.org Foundation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Back to the top
+
+
+ Snapcast
+
+ Copyright © 2014 - 2016 BadAix
+ Author: Johannes Pohl and contributors
+
+
+
License
+
+
Snapcast is licensed under the GNU General Public License, version 3 or
+ later (herein referred to as GPL).
+
+
How Can I Help?
+
+
If you find Snapcast useful, then I'd really appreciate it if you'd consider contributing to the project however you can.
+ Donating is the easiest.
+
+
You can donate Bitcoins here: 1Cm9WL99fyYSPbLvgnGbRihjb1GYZ5aZFz
+
+
+
+
Sources
+
+
The sources to this application can be retrieved at https://github.com/badaix/snapcast.
+
+
Libraries
+
+
Snapcast uses external libraries that make extensive use of the following persons' or companies' code:
+
+
+
+ Back to the top
+
+
+
+
+
+ 
+
+
+
+
+
GNU GENERAL PUBLIC LICENSE
+
+
Version 3, 29 June 2007
+
+
Copyright © 2007 Free Software Foundation, Inc. <
+ http://fsf.org/>
+
+
+ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
+
+
+ Preamble
+
+
The GNU General Public License is a free, copyleft license for software and other kinds of works.
+
+
The licenses for most software and other practical works are designed to take away your freedom to share and change the
+ works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions
+ of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General
+ Public License for most of our software; it applies also to any other work released this way by its authors. You can apply
+ it to your programs, too.
+
+
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make
+ sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive
+ source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and
+ that you know you can do these things.
+
+
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights.
+ Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities
+ to respect the freedom of others.
+
+
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients
+ the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must
+ show them these terms so they know their rights.
+
+
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer
+ you this License giving you legal permission to copy, distribute and/or modify it.
+
+
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software.
+ For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems
+ will not be attributed erroneously to authors of previous versions.
+
+
Some devices are designed to deny users access to install or run modified versions of the software inside them, although
+ the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the
+ software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely
+ where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those
+ products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains
+ in future versions of the GPL, as needed to protect the freedom of users.
+
+
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development
+ and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents
+ applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot
+ be used to render the program non-free.
+
+
The precise terms and conditions for copying, distribution and modification follow.
+
+
+ TERMS AND CONDITIONS
+
+
+ 0. Definitions.
+
+
“This License” refers to version 3 of the GNU General Public License.
+
+
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
+
+
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”.
+ “Licensees” and “recipients” may be individuals or organizations.
+
+
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission,
+ other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work
+ or a work “based on” the earlier work.
+
+
A “covered work” means either the unmodified Program or a work based on the Program.
+
+
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily
+ liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy.
+ Propagation includes copying, distribution (with or without modification), making available to the public, and in some
+ countries other activities as well.
+
+
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere
+ interaction with a user through a computer network, with no transfer of a copy, is not conveying.
+
+
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient
+ and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is
+ no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under
+ this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such
+ as a menu, a prominent item in the list meets this criterion.
+
+
+ 1. Source Code.
+
+
The “source code” for a work means the preferred form of the work for making modifications to it. “Object
+ code” means any non-source form of a work.
+
+
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards
+ body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers
+ working in that language.
+
+
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is
+ included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves
+ only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation
+ is available to the public in source code form. A “Major Component”, in this context, means a major essential
+ component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs,
+ or a compiler used to produce the work, or an object code interpreter used to run it.
+
+
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install,
+ and (for an executable work) run the object code and to modify the work, including scripts to control those activities.
+ However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs
+ which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding
+ Source includes interface definition files associated with source files for the work, and the source code for shared libraries
+ and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication
+ or control flow between those subprograms and other parts of the work.
+
+
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding
+ Source.
+
+
+
The Corresponding Source for a work in source code form is that same work.
+
+
+ 2. Basic Permissions.
+
+
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided
+ the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program.
+ The output from running a covered work is covered by this License only if the output, given its content, constitutes a
+ covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
+
+
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise
+ remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively
+ for you, or provide you with facilities for running those works, provided that you comply with the terms of this License
+ in conveying all material for which you do not control copyright. Those thus making or running the covered works for you
+ must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies
+ of your copyrighted material outside their relationship with you.
+
+
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed;
+ section 10 makes it unnecessary.
+
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations
+ under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting
+ circumvention of such measures.
+
+
+
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent
+ such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim
+ any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or
+ third parties' legal rights to forbid circumvention of technological measures.
+
+
+ 4. Conveying Verbatim Copies.
+
+
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously
+ and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License
+ and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence
+ of any warranty; and give all recipients a copy of this License along with the Program.
+
+
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for
+ a fee.
+
+
+ 5. Conveying Modified Source Versions.
+
+
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source
+ code under the terms of section 4, provided that you also meet all of these conditions:
+
+
+ - a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
+
+
+ - b) The work must carry prominent notices stating that it is released under this License and any conditions added under
+ section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
+
+
+ - c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all
+ its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way,
+ but it does not invalidate such permission if you have separately received it.
+
+
+ - d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has
+ interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
+
+
+
+
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of
+ the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage
+ or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used
+ to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a
+ covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
+
+
+ 6. Conveying Non-Source Forms.
+
+
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the
+ machine-readable Corresponding Source under the terms of this License, in one of these ways:
+
+
+ - a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied
+ by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
+
+
+ - b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied
+ by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support
+ for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for
+ all the software in the product that is covered by this License, on a durable physical medium customarily used for software
+ interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2)
+ access to copy the Corresponding Source from a network server at no charge.
+
+
+ - c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer,
+ in accord with subsection 6b.
+
+
+ - d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access
+ to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients
+ to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server,
+ the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying
+ facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source.
+ Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as
+ long as needed to satisfy these requirements.
+
+
+ - e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no charge under subsection 6d.
+
+
+
+
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library,
+ need not be included in conveying the object code work.
+
+
A “User Product” is either (1) a “consumer product”, which means any tangible personal property
+ which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation
+ into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of
+ coverage. For a particular product received by a particular user, “normally used” refers to a typical or common
+ use of that class of product, regardless of the status of the particular user or of the way in which the particular user
+ actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the
+ product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode
+ of use of the product.
+
+
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information
+ required to install and execute modified versions of a covered work in that User Product from a modified version of its
+ Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code
+ is in no case prevented or interfered with solely because modification has been made.
+
+
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying
+ occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient
+ in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed
+ under this section must be accompanied by the Installation Information. But this requirement does not apply if neither
+ you nor any third party retains the ability to install modified object code on the User Product (for example, the work
+ has been installed in ROM).
+
+
The requirement to provide Installation Information does not include a requirement to continue to provide support service,
+ warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which
+ it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely
+ affects the operation of the network or violates the rules and protocols for communication across the network.
+
+
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that
+ is publicly documented (and with an implementation available to the public in source code form), and must require no special
+ password or key for unpacking, reading or copying.
+
+
+ 7. Additional Terms.
+
+
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one
+ or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though
+ they were included in this License, to the extent that they are valid under applicable law. If additional permissions
+ apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains
+ governed by this License without regard to the additional permissions.
+
+
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from
+ any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the
+ work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give
+ appropriate copyright permission.
+
+
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by
+ the copyright holders of that material) supplement the terms of this License with terms:
+
+
+ - a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
+
+
+ - b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate
+ Legal Notices displayed by works containing it; or
+
+
+ - c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material
+ be marked in reasonable ways as different from the original version; or
+
+
+ - d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
+
+
+ - e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
+
+
+ - f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified
+ versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual
+ assumptions directly impose on those licensors and authors.
+
+
+
+
All other non-permissive additional terms are considered “further restrictions” within the meaning of section
+ 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License
+ along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction
+ but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms
+ of that license document, provided that the further restriction does not survive such relicensing or conveying.
+
+
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement
+ of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
+
+
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as
+ exceptions; the above requirements apply either way.
+
+
+ 8. Termination.
+
+
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to
+ propagate or modify it is void, and will automatically terminate your rights under this License (including any patent
+ licenses granted under the third paragraph of section 11).
+
+
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated
+ (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently,
+ if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
+
+
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you
+ of the violation by some reasonable means, this is the first time you have received notice of violation of this License
+ (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
+
+
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights
+ from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to
+ receive new licenses for the same material under section 10.
+
+
+ 9. Acceptance Not Required for Having Copies.
+
+
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of
+ a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not
+ require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered
+ work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered
+ work, you indicate your acceptance of this License to do so.
+
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run,
+ modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties
+ with this License.
+
+
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets
+ of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity
+ transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work
+ the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the
+ Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable
+ efforts.
+
+
+
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example,
+ you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you
+ may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed
+ by making, using, selling, offering for sale, or importing the Program or any portion of it.
+
+
+ 11. Patents.
+
+
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which
+ the Program is based. The work thus licensed is called the contributor's “contributor version”.
+
+
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether
+ already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making,
+ using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of
+ further modification of the contributor version. For purposes of this definition, “control” includes the right
+ to grant patent sublicenses in a manner consistent with the requirements of this License.
+
+
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent
+ claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor
+ version.
+
+
+
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated,
+ not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement).
+ To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a
+ patent against the party.
+
+
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available
+ for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or
+ other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange
+ to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent
+ with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying”
+ means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your
+ recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that
+ you have reason to believe are valid.
+
+
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance
+ of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use,
+ propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended
+ to all recipients of the covered work and works based on it.
+
+
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the
+ exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this
+ License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business
+ of distributing software, under which you make payment to the third party based on the extent of your activity of conveying
+ the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a
+ discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those
+ copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work,
+ unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
+
+
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement
+ that may otherwise be available to you under applicable patent law.
+
+
+ 12. No Surrender of Others' Freedom.
+
+
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy
+ simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying
+ from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to
+ refrain entirely from conveying the Program.
+
+
+ 13. Use with the GNU Affero General Public License.
+
+
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work
+ licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting
+ work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements
+ of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination
+ as such.
+
+
+ 14. Revised Versions of this License.
+
+
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time.
+ Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or
+ concerns.
+
+
+
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the
+ GNU General Public License “or any later version” applies to it, you have the option of following the terms
+ and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the
+ Program does not specify a version number of the GNU General Public License, you may choose any version ever published
+ by the Free Software Foundation.
+
+
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that
+ proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
+
+
Later license versions may give you additional or different permissions. However, no additional obligations are imposed
+ on any author or copyright holder as a result of your choosing to follow a later version.
+
+
+ 15. Disclaimer of Warranty.
+
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING
+ THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
+ EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
+ YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+
+ 16. Limitation of Liability.
+
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+ MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+ TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+
+ 17. Interpretation of Sections 15 and 16.
+
+
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to
+ their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability
+ in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return
+ for a fee.
+
+ Back to the top
+
+ Xiph.org BSD-like license
+
+ Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
+ conditions are met:
+
+
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+
+ Back to the top
\ No newline at end of file
From f77f58e6103f8cab94882bb7ac29c11a8d8f02c4 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Fri, 21 Oct 2016 10:02:31 +0200
Subject: [PATCH 18/24] Update build.md
---
doc/build.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/doc/build.md b/doc/build.md
index c6db9ce5..68fffc3f 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -129,13 +129,13 @@ Cross compilation for Android is done with the [Android NDK](http://developer.an
###Android NDK setup
http://developer.android.com/ndk/guides/standalone_toolchain.html
- 1. Download NDK: `http://dl.google.com/android/repository/android-ndk-r12b-linux-x86_64.zip`
- 2. Extract to: `/SOME/LOCAL/PATH/android-ndk-r12b`
+ 1. Download NDK: `https://dl.google.com/android/repository/android-ndk-r13-linux-x86_64.zip`
+ 2. Extract to: `/SOME/LOCAL/PATH/android-ndk-r13`
3. Setup toolchain somewhere in your home dir (``):
````
-$ cd /SOME/LOCAL/PATH/android-ndk-r10e/build/tools
-$ ./make-standalone-toolchain.sh --arch=arm --platform=android-14 --install-dir= --ndk-dir=/SOME/LOCAL/PATH/android-ndk-r12b
+$ cd /SOME/LOCAL/PATH/android-ndk-r13/build/tools
+$ ./make_standalone_toolchain.py --arch arm --api 14 --install-dir
````
###Build Snapclient
@@ -184,7 +184,7 @@ Within the OpenWrt directory create symbolic links to the Snapcast source direct
Build Snapcast:
$ cd
- $ make package/sxx/snapcast/clean V=s
- $ make package/sxx/snapcast/compile -j1 V=s
+ $ make package/sxx/snapcast/clean
+ $ make package/sxx/snapcast/compile
-The packaged `ipk` files are in `/bin/ar71xx/packages/base/snap[client|server]_0.6.0_ar71xx.ipk`
+The packaged `ipk` files are in `/bin/ar71xx/packages/base/snap[client|server]_x.x.x_ar71xx.ipk`
From de213a656f1f2bd65fa0a2f459962a1d80a1b938 Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Fri, 21 Oct 2016 10:03:52 +0200
Subject: [PATCH 19/24] Update build.md
---
doc/build.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/doc/build.md b/doc/build.md
index 68fffc3f..5e42421f 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -108,9 +108,9 @@ Start and stop the server with `sudo service snapserver start` and `sudo service
2. Install [Homebrew](http://brew.sh)
3. Install the required libs
- ```
- $ brew install flac libvorbis
- ```
+```
+$ brew install flac libvorbis
+```
###Build Snapclient
`cd` into the Snapclient src-root directory:
From 05a9b406585df2613b8e3ac6a88623a1ed6f10a9 Mon Sep 17 00:00:00 2001
From: badaix
Date: Fri, 21 Oct 2016 10:14:02 +0200
Subject: [PATCH 20/24] updated gradle
---
.../Snapcast/src/main/java/de/badaix/snapcast/ClientItem.java | 1 -
android/Snapcast/src/main/res/layout-large/client_info.xml | 3 ++-
android/Snapcast/src/main/res/layout/client_info.xml | 3 ++-
android/build.gradle | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/android/Snapcast/src/main/java/de/badaix/snapcast/ClientItem.java b/android/Snapcast/src/main/java/de/badaix/snapcast/ClientItem.java
index 50e2442f..16590717 100644
--- a/android/Snapcast/src/main/java/de/badaix/snapcast/ClientItem.java
+++ b/android/Snapcast/src/main/java/de/badaix/snapcast/ClientItem.java
@@ -56,7 +56,6 @@ public class ClientItem extends LinearLayout implements SeekBar.OnSeekBarChangeL
ibMute.setOnClickListener(this);
ibOverflow = (ImageButton) findViewById(R.id.ibOverflow);
ibOverflow.setOnClickListener(this);
- volumeSeekBar.setMax(100);
setClient(client);
volumeSeekBar.setOnSeekBarChangeListener(this);
this.server = server;
diff --git a/android/Snapcast/src/main/res/layout-large/client_info.xml b/android/Snapcast/src/main/res/layout-large/client_info.xml
index b2413bd3..f53c63b7 100644
--- a/android/Snapcast/src/main/res/layout-large/client_info.xml
+++ b/android/Snapcast/src/main/res/layout-large/client_info.xml
@@ -67,7 +67,8 @@
android:id="@+id/volumeSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"/>
+ android:layout_gravity="center_vertical"
+ android:max="100"/>
diff --git a/android/Snapcast/src/main/res/layout/client_info.xml b/android/Snapcast/src/main/res/layout/client_info.xml
index 651d8b88..a73823b3 100644
--- a/android/Snapcast/src/main/res/layout/client_info.xml
+++ b/android/Snapcast/src/main/res/layout/client_info.xml
@@ -86,7 +86,8 @@
android:id="@+id/volumeSeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"/>
+ android:layout_gravity="center_vertical"
+ android:max="100"/>
diff --git a/android/build.gradle b/android/build.gradle
index a3330d48..c20bca14 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.0'
+ classpath 'com.android.tools.build:gradle:2.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
From 86bb3d5a7714b081e3afad86eb838dca66f5d6cb Mon Sep 17 00:00:00 2001
From: badaix
Date: Sat, 22 Oct 2016 12:33:42 +0200
Subject: [PATCH 21/24] banner instead of heading
---
.../src/main/assets/files/Snapcast_800.png | Bin 0 -> 21406 bytes
.../Snapcast/src/main/assets/files/about.html | 3 +--
2 files changed, 1 insertion(+), 2 deletions(-)
create mode 100644 android/Snapcast/src/main/assets/files/Snapcast_800.png
diff --git a/android/Snapcast/src/main/assets/files/Snapcast_800.png b/android/Snapcast/src/main/assets/files/Snapcast_800.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6770abf501a683d36d345114f58091f15546ab8
GIT binary patch
literal 21406
zcma&OWpEtf&LuqNF^?%`X6BfgnUk2AVrCjMGc&Ut#~5?W3^6k^Gqe49_r7;`e||O9
z(_LLP-D*9Oj*g_BaAid)WCT0}004k2BQ35906>v^9{U4fKfk#b*E>FUutsuH;((9;
z^~q~5P5e9qZ!fLs^!ba0|FuDg(qy`So`iFjQILS!1fn29Bi_yWv;zPn02y%+b@%1d
zY&UmPjg}7~t26I$nd+IpELb=O09vxQ2xk~(U>M0)4pFN2*ERpW+HU}B!8R?n
zL(#_FgOWI1yb&D>VIQUex-!%(WU?@=GLkq1JPiplh5xrav_+Ux=*GY*sIP(RWHHyS
zZcFPsOxr&;^kn`k*ys-ol4leHAL!c7g{!~R*<|)8P%+T8%q$pb0CfmcVeymS4YyX(
zK~ICDAWA;J=sbOh97(u|@WMdxkV}X`F#=0wy8k|-sX8LaTPRG8&BsSINo-eqQwMZ`
z*dKxz_O&*@Vf;cEeu_$#1B9bekPBxk=J60|?5y_kE`WWW{C{+WO9&~>?1UzjIZ5@_
zY;RANC~}IL1(g*8UyRTnG6mx?PtYEQ#_n8Te7oJX;n(S>hw}c_AqnAh&-A~##%u;m
zjTVFz&g_4<0TK(Ppr`}6Ar?y&><_n8@!!xXG!3=w{Ct4!0HL=a?(shG5jA;OA-`9@
z=Kn0!Zvd_MZQ|67hz`OjsycSY;h|?YP^=NGBsi~7`z|BB1j11T;9D?W-Q
z#Zj2bLlOl2BnbKr0T=8m;e)vCD!7}E!KvD4X9aV}?C*(Cnas^A%uEmYde6fCUxoD}
z#2I3cRYlU@!#tU88ryV!|JAuI9EhUEWP;X=wW;o}jWR{MIWIaz5T+0^B!0tHhZ7XI
zd_`j2@}*om)Py_e5I6+^!wPFGj>ROGhRf83_okps_l{5wjo2K0F*oK%swJfXZkN~)cI
zsk-^{Ts~jKTYYTeTR6{Y{dmJ
zRD28vQ0|lACR#)P9{tZ_j|zta{`hrMp?L}GK3*JRl9UgU;?ar_ph+=CGGU6o5^>ip
zfKih}3N%@sz-f0bVM#N^F9vA~X!XBIbw6;1$J`Q^-)SstdP;+g#e=V>{Nm6|>S3wB
z!f$;eF-`p$c~)LJ@4
zJY=!&+vTNq<#a)A8W`9a5Gk{x5D_`~-QDB<{NMg*>URp&meG5y?O*7p(c92#EBL+f
z=xf-wBvO>0r0!&naiDEUgX)}qsm0O4dy}*qA!P??8fo>EOAut+{#@U}dxrB`;p3Pc
z0FQL++-grOFRs>+3!
zymU%y_z(K9bqqH+PMvQxiiJ=>(|^jEm*hyxQZZq2ldd1ExdAB6ViJTUo$|q8w0rgI
z3&B^>!^q?1jig5{5_6uuO8WPX8K2P$ikA(F3h^Mv6)hc&mrKC6D>3aqn4+7jd>rb7
z$C$}BL;|2gw)rvg;RUjn`ck+np1=UF?tioz3c~5Y%0n9MJa%tEc^UN7{EutH_KY$7-dZ#8S;VV{vIB-P3Zlh9bO52^g~e^vfmG~Kt>C-
zT>yus}_h_8q`*
zt^&3|9ZBh0t;m0V%XSoi2KqOhcxZjsRWRB)D;Y_SN>gpIMVneCr^)c4l3@ksO)C
zt3U3x!VIx9#k)NOR8BueGsmym3zVsQ0aFfpi7{y`BCJLtVa{uUjYaxQMI^%8Y}d}t
z)8|S(@V{>yvpr;~q*wD3K7JXv`F~(xlSAMTorg)`ZH?`?b(^^hjq0F~&x+S?<5j41}PGwxjg5G9~f=*J=!p?~m}iWVagFlgrP=rh57+c=@>DZ|`eN-+^;!G?T8uGNENUMv3vUkEmu#?>QLhlKR-To%%6?9D?WjPZtm>o>!TVo>=Q
zN-8?~*`Vd?f^WviH(*ed9||a*jt=!zD8d|!X)^ojjoJfMdFd)3=eT227dM`*7WP{M1So%d@;|$f_U+xynkc`N^vorgk`!b+azekKCv&{s$iL3d8QV4_85|LYq`
zztl=cGx|sbZete6PdsAnF8cWQL)Mv4!9q(I4@@SiBW6v~)zn}w0_ZpvaQcw*n4NsTnGB-!DupvI#ibq%tU4O
zF81rP1E;Tj@M5XgNg>adnp5bE?*`$ZvFY%TN~q9{M)cdI=rW?BJG~C%dZTxEdUvlO
zadwS;1OGRht~)z~V1r*Ide>)+eA5JupVe+BGlaYm1w@Gb;U^ZA)%x}pu>ZYNR>~xX
z>g%4#uXQi>9@@eRTINeUy*$e&3Ft99*Jr)JC}oa2q=<({{`g;%h8xE3Pz1JiwLXRdB>#yWu%l%+en^Wt
zw(O4WgXHG;S5vx&@n0))KD5jD>*W?TPW~=Ty&f-&ZCJpFsBW;;+#e!JOFLQm5kcL;5f^uggs
zDaaMPyguf4xfqBBbMM^YuOY6Ck6yf27}y3eYhV30a2&1Y5J6X>O6@0M4omrYtcB>6
zbDUlor`?P(J>d^Cy3O2POVD)Eay%9$F+G1ZMPwRP#6<0v`ndvC-}a>2ru!kuOEo20
z;b(D1iaGWSEioe$z>u-1K;9E2hDj#(!yWmf6x(g4fzLzVcFYJ-8{
z3(Wx~d%02`(T4CkB1b)TDqklF&O7F7ir+nC_!~O0-@jpi%o>^-x%}FAu
zLdWB5gF=%^Ac7HqTJxJ{?s!=Gfg9IfeR?B3u!+;XMYR%?zd^^a-%{87PFtFx9%g>O
zFrQ6jehE~>?ozna|GzeMO)1=$kC@$FyqhR6evUonzm)2qh$~C^c~|6#+z{Cd>uPn4
zxP7QVVj9eX0R-w?4TU_ASSJBiTCcoOV@!`RQ^qaV~2q*^%XXIPa^*C
z7R8nM18JD?!GweScai&jDb30Yg7K8wF*#X~a54U+TQxx$={sg*b*>w~`P${C55#YRa4Q*r6cqbS+q&*n
zDHg`BqQON0nw}lmmBIM`umE~tUfiCmQ1Xk^gjlzYBYwYYD8v2K{6yn|y|dheD&JOJ
za37Vo-w0F{vP+O{Q*Zr3*ZE#9Rl{9}GWfB%*h{r>0;{hi7edypyrejgBRsk(VHu3S
z9#g8UM?gv#gg;z9Y{0Z#IQ9#v{wgTxi$6V_AfwQZZcYVVD@6u`FZ
z33UCJib>nqX49LpA7IMqN)owppvX?AkfP_xh6p#1L-8m_od`^AyXT`jA_q@<<=QSj
zTA@F%(N1;>M~0?YpIbdEn2&qiG`Wq-6D3=p_$Z=CaSlVkvEYUo5
zD%76@$k7>_@b{KF)XIQv<5D_#rnAMi-IViY#vpksm%e;}NQUdpj-
zLZp?k?MU2Bd0BSiF;Y`3GKr1+b0Zj(_f$z7xB8fRdBLAm2cu4WM^R_3m`X$@a+Ap+
z=muG7_Zqw8O$tZF1j{JMVUa66=buE}5%mkzwqUyqt9cI2ZP#K_N^wY7Lb{Yy!jjC(
zC$#8S-i^m3o~#jzQ@|qu2-n~0sE_~mj@G8qePjLqM4JQ1qNlB)EmeEJ^YYu|sIKvs
z%ad~{>F}h4+i~CN+v5e$H0!`$`%nD;HJLiK^(Jl89{YH#ACz1RxjNmVPUMbJXQJ5H
zz(je}8oKyaJ#*#CV1?R%M|1^Yk-Hf6ht~T-ms>+_Qg$n8yuf`*X_D^H>5U8%zETDl
z;KN}Mk7E4`I=%b_P@{hkAqKWwSZ0c1;dxCs7TUq@vu_{`;|^a`((ErKyB
zBvRzL!gp=<>ze{oxH^LGUCDz2?dfS&4iHw4q5e{2mVRX}KH5{t3v~a1{FA$1N_Z+O
zl4j{d)?RicIDVca(hSFYZsLp{`3f`1`IBV?UZNJGnUvqvY&kC8T*o-$;*zuNA-z_*
zp(&jeP^7e9!zr6#YS=mO*XR}MJGegTc3u$?Ibrj@l
z7CO7;A``mL65LTt!Apfa9SSN`>&Sw~F60wMI4GSu<)60c>s|tYGM=Nlr#@S!Ok3Z?
zm<2h2soMgb;#Yb?DE(@#rLKhfN;`#4trQ^-4c@f!MxI{b>qF2qLZIv_vHA`aUK_<&
z?dbInT=An-6qORJa9>}b@1Rgz0s~qBr}bL#hE9iUw)?VacZgxDrTKn$*c0FqwE`_9
zXlYCA`c|d+f*B$f@*%i@V*HR^^ObQ^3Z~6hgnPgZfC?BBF7SK!4xrqUdzIhp?dpbU
z>x}MtOS_y-J*1)43)|5`IEB{%WT6T2NwQBseRNNbpROytJCcM3Jlhl7Ar6xB^aWVw
zB?S%K;C3x_q`K1p2HJmPmD{2&FNJ*d+IPfvSaG^{#t@*1_s2*y_
zK#;n|oTG5`YPX&AkF4QLWc%V>@YKF4uAlwW=pq!KNE2=wJ7?-&3y3uO;=)nS$c@x!
zG@W@Q{xBbQtau7h=*04nwifcHFlYllb70d*5Z-J^#nze~=~dSTvUYW_fNutC_0INq
zGsyQ~$D&fYB%kJIBPDdwmv9LTx_9p$Y~G;@%Dr0J^FS<3xvLUnKHd+EK~f#9Q=^OF1Y(qRBU_XL)*B1WXf^!ZtB$Zi~)5<frBA;CGocVkgbU)G4vLZS_gMs>3cNmmEn;r=jD?!U;~kWQ}o5b>=E2zi5ZDHstg~8Rl&L7tE=9e
zFmnfJ$e0H?LGRmZZhiP1|LbNHmtYLHXhXNYLygMulFqv4EWn92vlv1W+
zdm5c~xH|Veih5F*nvZ>cTAcjhmhy57UNhfWWty98PpFr3lwcDIpd%Lk?WI6qO{@of
zGqsC7{}G>75mpa|31&YkzP7U49e*A6JuyBVO#mm+{0>Xfw=CJzAjyzF#~03r<=;vN
z@(v9DWDYF7aO*qU>se@weJomltbjEByo0Dx*y;M?_-phxTD%D
z^`})9>MX0(<=%4cXDpMWoFz&>|L14VjLggzOtN<0O0+XH+}@4+D&`_f#v
zbBb*l8-CI|w@e>;8=A0xub9$J-nz14WHvs(n6Ufd{-sizrVttzGKJvFm>8;*gZuz7eK{IfwQc0pLR&3{m_08sQBg
zc%{c`NBDnq2Q|ziT{Th}U-Jv`{#$4@<$wnj|GOz`6VJ*#fh}NCPjL;4)AJ17X=>{|
z#~v@)O2@c#6SR2_K+1gdTa3D)6?*gu(q5JT&(6)&nvLNFkbIh|241NNYSu3?kS&i*
zab-Zt!qo}!aLo=Do2sJ8bIV~D`IZFGl^;610k>3M#2NB@mtEK;$l<4gm*UW@mV@H{
z6M<*~50lXFdW6Tpwu5V1s1Y5nw+jKVI^F>GlAEg3f;%k=Ugde18+W4`qO(^$8}DaF
z#4zHYo?cN4_pG4wz9rwVMwMvz6aI0OrsD4qkQo>#C5tY7Xiv>`#`3uVg)Y;fpw{{jiw-r2So&>s}wax!1*^X3^qaya)gmHHUgexNFg(wdq8
zby48{(MeKZc-}}nxZ>JG%bG<>QSgTuf>Z?|p&X#`aB#|A!g-#Any(=R$(v^Xo5b%I
zo5xUhWElbMg^w7KnV~g|T^pRaEbeD{H&SdDp)*?Q1z!s?x)0()Do)`LF@a9c!=<
z%xmkLOS1m*`~y~0Q@b|F>RcRK0jhMXH%(2*5S#)n3=0L%uCa2A*&*P
zHNRX#0pgUL^w2Byq+N&X5A*&|Q(?%Wf}~zQX~EpU7^vj6y`WtRCJxa-n{{7dZ@~_mn;yWV~ow&Z{$8V$S0SB9hB5Meg_?
zY2Gz>1?)@~8)33GeH%|E-&8}xW;fLtSQU`ir6j~uFwI4i`N2uRIHko;(SJZe-2?Ot
zPbnC&(UZGAKJ5%S7{ceAn|LEP{)0|`#&2UqZebcV1<*M%(~1HoXcam;tq(y4AVaH#
z20c~fV@5lVz~laYoJ2?pwW#<#*DDnU6m8Zd4hqz+Wj2Ld6ET^-I?En|C`ziYudn$z
zM~8=x|MLAw_Q4PyL1yw6fv$te>ciBUY|7F+Vr0K#!rWHMm?eLkE
z4%aaSYlkpwl&;uF5r``UFS?~gO>^=v`9e3+g-~|N_fQCoH;Bc%eKAHL+)adH(P%n_
z4nQMK_Rz{j1Y_W*SR4sq8)c~Mi=tgpS}W!hr^2aWSGB5t;|d&2Kkw8tMrP8P)Y1W?sZL7do7XKXx9^3$@jr|5vERJs?!OhqZC`lQ{xnFwP2iO
zif;@4#|Tr#;fw18sJxf7`i=s%>E=7?r+j6x3^`Mjr$1L3ZGP+i{W5U_J9|^;c7^uN
zpxZX)OIop!^Nkzpg{j1EgJI8O`J0hLcmRAN}zNt9zcUi@dQXvOPku4+W3
zcGLCw--`m+rMot+D>OQgdMkw8iNI1cj|ryRHhez7;mS=QyZy`7cG3luqC@i^2lbhe
ze_O(sW6(`)Uik;ADr&3@Yp%rOy}TS$5I5cS_kA54j8EItTb!oD%w9%#M|+|am?Vu{
z!e8MGGhp_6pf}lFX&3`JOcl-S73c`%J5eKxrCPlH%|P+Poin(8ajRK$XY&Xu$OBl-}dIa
zYxt-Lh=Cx2)B}8j;2Ub+7*ft-VRw*d`|m6Osd04IR}vdydYDn0F42(AlltDp`(tm|
zX8O=QRQQR=V)_ll+={@x6IY;AUko1oY4Grvj!@U$zVJ(5Y5#OJz7$~EC5?vUD}kM*
zf~2B!MG4p2WTxOHf3?2u2>X?HZfh&AmbP}N4j89$s{rpk7-gD-Y-Wc!og-`M5*J27SbYoQuXc#dIFs*#s
zwePN_H>zKUe!{Pmqcy@DFO2TUmo{kAcV~NEo=oo+8BuBEa;9L!VhL35`rA?NTT_?IZ+dd-U(hMf%!dCNg2!03H8S-}&Zt?5~T@>bj
zffb^g+!0~~$4rbk2n-^N8ZZv`zBd_B-OQ_{CB_114IW5RDyTn9Yb%BrPb<+L`6fAx
zAb0bEr(J@|@Q&THbHt@R!t;1?7)75e(3W{qWBZcCHnt1TRI0Aeab(KW+n+qOt&BBzNW(jqfM_#5einoqk`9NUix#qnz-kgWT+n9jZFtBI6O$WQjLGI4-6Nrh?Ec)_hg@jWwuOjjztRiK_
z_wspsDWSL(7R__=Hme2*`oXsoMOu@6tPd~oAjC1Ih0j#>asqYD%=hI7utdMd%xYSW
z!dsrCF-f-IuB^SEJT9N=5h>z||6Fn6b#`?6W`|A+XexMn%5T>_%;WUpTLXefqsp9g
zf0ZaD#T)YO>a#rB``7-nmJdA`WMMbcaFzD#gF7EgG7*HwU`uA+8H7=+-^uM)5`#!U
zbb_Tdpksa0a@@j|FaD#AXszRmAK@25u<$3W+d~y)yqEQp&oyEZ7p6d$ln!<}=}ZWF
zIq!KYeV8Fd#^#ePoZqpbo(#$Oh1D4mkka7OqE^7_G`++e8H<4ZBujah4(f1l%Tcf=
zEs_Ce=F#DChR_Ls05j#KL^LwhrL)FhfRw5#K|gXT(NCEs_tQe3{pA{D$IvqPdsj(P1D1fY;
zo^MI7Rg(xMDV0*V%bA~x9*gSr*USSq<(jQFKot~k^uvo}6=BuJu3GQn?@?OcE`9Bu
z)C)WF69O!Y7-Lq@xV`N
z>!lrq`z~S|{R2*Gif*ATQ{p};ni*o+tVTAZ)KPpxNf&M;;%@{U^cE|n@w
zlpA;O02eKR6UUVBKH>gPYffe`nSh=4CP_#;{E9~!x1!ty7)y=F^%r4;;8ILE!fafq
zOZHC~X>7gGZhIO-dkH8<8~48`VX*!}Y?BeD$-Cdgji{B)?ZR0lm_*yn{CsmO
z;C9$Q%i*Pkz%gYXSr!bnn0EP)*njEYk%5(CMIQO52D6;uM+y#V1#YvEs8iowW!)Bq
zAnWayQ|Gkudy{TZ%5lyfHD7e0k#I-dz9sq1{t|fo*=%%@&;^qw-n?}G?IbzY0R2rc
z$VK3x|EGMw>ljbf!Qv%PspKZk2rChkTbjN*q*{Zi80rSsJ`2$~$p(JQziBJ^p#uv8
zrsaQ_eH(XE`JJzmRW3GV%E0iv=rZ$ve)Y0bZ04lX@T`LB@!?zA&$
z$J#Dijo%I0E*d)*K!_l~w4g=wG>oc=5|pi1xSssO4dfijn^nOg6@vJ@NCZ-Bh_I{6
zk23Xv2p!PU#h3g*A~|hi|Mp?V
zi+myOw4w)8gJ<1;=O$@L2Q&Zr)gzB-d3aJwgNC;FcdtEh7`+k*f#&e|nAHjpTHlZ6PvRh89Y>8uQu_%h(!Hg(AfR!VS$X
zJ5a!FT?18Mptv~G=rRj8pJHLOtUS%3TaURksR|8-cWkWx3nRLZtpA^$iJLCpP|?1o
zCeavI?*n}f>UxxVCh48Q&kiDM0pgkJS?MDHGzGuZsV2B=S5U|*%>~(O2alBxi#z&L
z)M7sVRAm4z!kH`>uNzGZg23-8=!fUQ<0XVSa?HABM7Y{Suy?3IXAH!9K)KJYgI5Ma
z3aglhyONMUEs0|oVFJ-o_%JQL6#?ukV)K_Bk)~Z0zc9jRXc1wn{PUU7qI*lKEqlK)3dXKPt{+yQ^K#A=2dZD_W+4K5cNYmEA
z|Fqkq9HeKhM(sxmjgQj3&&$~1?fCsF
zNQEQ&Hx&&Yke8q06SVB>UiuGbOKh7eF^i@-sy0dxNx!w?KJrji&CI7>q~o+uYsSK*
z>@~mM@}CWg%1`f6vu@#ji8MXEG?WiN-Z@o9>QW92#aVfZ`r}{0T71hGm?wua^mnEH
z8tfYTi(c2ts1|3YL_rKC&&!Z3KCh)EodkH@p(L;$1oT&X>tLu3zt5aJBJ^XK`)$O|
zhVADJMc2@v>$jPb&hq;otF-O0>x!({$czGCCXfaxHGaTZRtTOOp_xFyg`7pej%sjt{CwT+p9~f
zASMWsl)z*u;I#M^_A=w&gDQ!!nnHr7qU0`9r2d;XwtwrL
z7F3)g1rAEk&-pO$zN7G3NQ}?`u{Aq<8$&4?kk8IoPEycJuCkDDNxQ5*b2sNtVM*o|
zf4M0ydSFik=OP&3mC$ZLq)}`IcST+P{Q+_Q*Wi#hU8y&TwWD9~S1aX0O^?nq#lPOZ
zpoQfbgHPQG;^8Hyth%G^h_r$U2u_mIe1w`-W(3_K3YspaSLO&ZifF_k$hz%9`hL=^
z@f~P&Ygt7^Mrt-!W?`Myr{KE!~a5!sr
z=@yJ1F7hd{KiOpY8HmHpF8`_3)TzD7*m>634nfGyaQkH?gId(^doX$z!KTS3Vwz*?
z6G?>3Y7=D9L3)_Z#EQYhXyE_q?iwd7rOCRcyk2&u(S)iEJUYm3eos?v$3L~a*zhy$
z_{W*2uRH2mjKGa5-deUWF2UIuBWoj8+=$C8!j*g8xq(2Jt#SMnFS^d48}e5L9MPBc
zYC#ejliy!>uKG?Tsp!Ig`A(|eO$*jNhbcn#OEtAY_|yKOUu83S^3kM9QnZEc^x8_2
z4lmKjT!slVyX8oo#;H~S`Mg5DyQfu^cLMf}WI3zGX1Ez(_gADeL>wfDBue^?Xc>qa
z#p2uqqbwD<=hFeNX(~w_ED6ph5Kl*y@Ar{PPRHa`KgwK4mn+cI-Lr4yF39)V;OY;3
zm}b-)I9t}TeJ&Jv{TJKpGE4ll@*4&m2=>P^2TK$(7wb$BwXA{;2PrIlpZ%Z($LnKB
zO@5QRiAk&9I650)aH}|jHWhjJw8_dae?D~fBwK_jh+!&m?Nu(LP}ky}xy?mtiK*#a
zv^k}(|75;1-1{Ogy~LQ-y4AwM_1b0}+Cak1f|=H+6xq*q|43BRg(9{N&$2gMjod%<
zV_$5`>qFCP8IDPKaa~xBta5{q@yo?RtFV534=EjboKLoUow?!U%s3pQT><(Dt>!DA
z{RqSw6SvvFG!YdQw3GQtvGVRxMQ01_XnVPE`IjHA4^9y816IA@7=R`lqNbC$t7FUO
z0Lr5h2*o1!H!p`5IbHNmZw&Qca!#U^Q+Lsxfd?}~hgaYzta->%!_`_Rr)
zmr~50o9jP|lk}0M40Y7@{)8c!KzgEW53H%45e22n=4g{_pf{!!R`8Jsp4LHa?H+|-baq%W
zEoX2F(}(lhqKHqcAu|M-E4NhEvhwFJMM~`;ZkmqZ=p@=;5X~7}n?OkH%}mtWh`t9l
zi4B>!V2f&d5vQffravrRm_%MtSp~%UUuOuDAcF&pdcg-D^_vq-9#SosD`m
zwKL#}s#Qh#lI
zsS^)VjTjk`{lcUpt)ZdODK6c#f{nh`nsIwfoR^_5QR)V=Zh`Whxs&9kK{el&3ES2r
z0JUE-)wu1t+h8W+x)
zK{4qmN^@L?gJz0foI)8+mI3W9T7wS
z5SQDLWN9NJBGUNWY;)m{+I<+wp|$O#&cH}n=rd3J7RVE#xaUdi!YL*|&?VO^inDbqmY6Z#D->(JY3oju!e~^d
zi-zuI-7w1G@W^~{+*GJ1S&09jzb>y>Z9<9*-rIewBPvGdaaen)wF39SsEl%(YZoM1
zDdrv&&y=DBB(PWNLj6+vO}~=+MwIdrwZq2S8R&6WU35RAPpIloWn|QqXYir(!v0tt
znAqeDj?EX!hrT-nKl(w;iyK2Ij3#3(pE5|i^aTF+92WP8%*U0pw{v6uAuYKfS8a5t
zh7>a((eX#01}*vvnw3%Da0mnGV-*TANH#zoI1Fgy|LfHx$n>XvMj$u*JTZVRZQSef%js
zWp8B4mFCkaIP!v8%BS%gE4)A+*JM9oM3%v9!NK?Wufk#9
z(kH2lL84^X?;*}6@$h1JdBE^yWrB#f&l#Q=mGIA!TgvVT;#7I7UOP(xstfruNXTr3
z?hhn$iJdzErONB$p#JLYsntC9W3v?y9_aftNs>#ZK!C^t;I79();~p(OM7I}&
zgtvotl*3&};A}tclpZZUtH>$})#*0UA~kzo)OT(M{*V%6!4Hy0Y$Q6&LyN2t#;vbb
zaxX6x-JM(sLfx8Gj824{}n9zx0XbFgo`BOuztZ)zo
zwS*3gDWdxVJPa!VwB%N}nfy6B*C@(1p$-O+MG8Ug4}ukLRVyVqNb1BM(7Y@}F~h`x
zv=w+I1yD3O$XIec$EtWqJ?Sr#t#7?_j22e21Fn`hiGVcvdi$?kZSd
z?IR`H7FQNhsxr1FbfblFIG1^ssMJ|-B33vTq94tV=m-Wb$(oVN;Rd4muM7-PX`tLX
z@Su-soj%4;wD4!@H}rCqEG5I?uXqZ>k_tPQkxct~NeaYE*ETE&xyTw;uNZFK)m)<1
zOsMkfMhoLY@#)4Y+Ds@O$INg4dt-&yFt)ZL3~kWo9B3H&Li$---a2!T+Zvn#Gx07124JsHz=3dFS257J0Wl->M1i$04n@&Zn1Xe
znK>fp8gAxIbM=5@e3!RE=JG)nnTZZ>2dqAUdqH`R?(VwqEyjhPM~+S?c)pn7gF4%r
zHo5uhw8IY8aGoCr$4^XV92^k%o_uA@l4_bKKTt+v79NxY&ms6cxWn+P1&~e#o65L8
zCq^gkUQ>x?eSmbRh+ZBv;!i#-AE^|Hf{+k&Fn0R0N8x4R^1NuQJBalIoFwr_W0%XJ
zD#MIR>#&vfR77)=Wn)&C|`{QBSwaSj{>?{TCcDdKzU*d?bN#zzg8)^=_?
z*2qz}$zx2rAjN|M51_ggP+=A*RVlnU3S3GFG%Lg8pIG$nXp8tKa4wN!^SIusB5PR_AFIO=GIbg|t{bCsD+*gEGfSCKx}oVacvbP%8t=qf03
zd?$C=w7#r2Mqm9|Z?y=VKb;|keqSaQ1zprh&>D=Qv=uAC`T{4?v2%nBnQzeAJ39y?
z;&j|8`Eyg^^J(FXs~{8m1o5~@;2@?As;Bg-{V93ySfP+%EXS|F&0SkNyRWkcHK#g`
zH@2wQXq%G+DH|+`7i&(AI_rZRxeZ94^MRbzH^n5)uMFZHAkprt$Zs2
zOzGR?@d0}kvqHAMqC(8#e;-CdB%&BLpqa*dJ@p30nPMsUhAM$wzOezu{6KE*&^<0=
z`i8qcB_|!ht{_8{+l;Y0uuk_Q%}2Z7;9e&eLd@02Cx^G%x$MZ6K5rM+s>NUrL?^Mi
z_sruU+SKupv)3?2WYk4AyFt7fKbSh&XXxIXCy>1r&@bYom3e}seq;LmOvWo6r|F0d
zP5JVQN0lSPZc8hm=amG|&OFV8!Ai*Zy63g=eFB(zqP
zJ|Lg?^9WRmzIWYfcl^43t#x0xBECYW(HOI%JT
zFs`}#>n;8Pn(y1m*11{gQ9rGOIx$?Ntt4?Xfxr_uu3s|hmQ;N8bNW+@A1VD2*qMsn
zrdt+5tsFg($)E8%B{*c@+m9B>waZIHPXQ{uwO&s_$p9!neW(h*KR5N`O@2*hlQA?9
zEukb}{6~Rcu0jUCPAKZVnwUotq}|$aqs{6rW|l4a7UhY}Usr9(p*!5zYDY&=tl+BS
zAx6bcf=9&5cu4-ncE1&;ES<%!$6*Ls1eiU?>zV#n%NLr{e%OnHjiV%3?&~bUE?Q)hr#|GQs4Pgnu_-wbWP8Ztq0R5l~lTW9k
zlSS=_eZ0O2yZ9mN&`16yx#+9DjMYpe=7kG#9k@EmbXl*kN(Q{~BI)eOb^3^3uyrxn
zh8`fPEORsElk!C5;73C-_ho4M{j!G6qCEHfPs=3a%|y}{wSa7XH;
zA%EbH%{l)YTFbO5x~bwAnV-^S?w`mS4Nu&E3&NqDQt?l3c>87{yw`(*z$`8n5;9{?
z<@Zzm_Zz`=rkC3XN$LySIj*O#``88f&Y~ZpDpe4fu(lb|GGl|0(#@mjh9y*I&byo%g4X
zCkBZ~IyDGRmb2uFn)2qoQSVz2x4s2gDThgO7Q?Me-b9wp;BClTIwVQ2H9*JXWj%oZ
z7XC{7>M=tpXG_|!e^B)GH7V^EHD0vn4V#uezyIOy3AFTghpg$P5-(5fSfonfz%ccm
z`kS#qtB`pvl6IJc6Osnp_8SQCZ5t382VqW}dTZ}b;`Evd|8P{l5VKD%rs~`Bp!sI|
z7-u6VNNfwiMhZUEyq3bSPb3Tp*!;TbdtH-r)b$bk@gO-Q4PUBzJpg;nzLH~C5*u%I
z(JI39@O=~2V?DK8jAMyS-MZLUZ?O2YVe~bo#CV^7cu1TK^T5M9mgSN_-2cc|WBkz+
z>nphR`!hbuX3`-gdS_#f1o9-4*NXGO;OjkyWso2cS687d{?uTSj4d
zhC8#G;)k2Z{YHTZy^$9f-mQ~QMgluf79(1cc6vpo@)_bPRgtpgn0m7*WYiU5Om%CJ
zHgH7DVEc&WMy}={In4XK+pUzG?VNVO|A#Y$lOQaWAoM28-L+XySF8)eu@r?u2$B
z>kgUs7NSMV(0meiD0lXWlc=D99(&&c55bt?`)i!(6Wf}xb5|q&vYqsIyzz;+kDn3}
zFJ$
z^lQ=x>~|nz0fj2$1fu;{aO~|#YS8e>(wAm!Z|GVv{k}{`*1T{@XbD#TpB|aBd>i?u
zOQO?ORibcXx~)m(5$X4+c(VJ2KZODgOocL^|H0FOuBPsLkH@rh-Fz?K&Z19&{e#jT
zLJUvT@Zeq)F_9~8K4@KOsLr}x7L!+!!9C_bVvBZSFCu(My6#^wyHot9f`$?6c4hny
zm8VLIDBk{h-Bl=60)3XJ)q*Oc$iC?ZEI+xYvb9P$F%`IXyG_-FxwCbBXDx8)ByGPY
zaQ5^{T_+Z87QcUH{COo-b{!Z^O@Rl1O#VfF^_*(?G$^lH?d@-Hz^3j<4h{b&r%}lZ
z@~?vfO?9}*@~-mdD^fe~xHP@Ag3!uMh(z8pZ`OLGJD
z{dNDouZ$A_z`*!l{|f-??Mt_oICa|li#ab-e;6H0i#B54Cpy8~2i}&k5*}4wD*WrJ
zi07U!I>+mumAb!m_dkBTl6X#7g(-5U6j=CmiE*P%I;fubD7*&m$h5hm4=*rLwLd$4
zjyo5+e&A;>%WCsRcAhZ>v~~vA%anAX)**wxy9OCgk!mA|f&m=Vo5f9YLLE1Qo1TDT
znaQoUnkb+5h;p6J8Xj1F%y%WRzs7&nOXr8@{(%QuSZ8Q@e8cTHR9c^Rq#^EQ9AOB=
zAGGHF4(eyKygi7Ob`mWNxK;f(&gOl-1HKzGB{W2x(uyMnj0;ek1Ce8AD4K-Y3dTT#
zsykcc=6_0Z=2G=3B4nb3g_=4PKVTY
zrRi^&N)NHP7@+v@19*F*diUl>gR4?L2}VBm!;)XtVXBGwb|?xC4g3vLw)PY|99$Yc
ze=Pau1xzoYd_2=%!jypinjO|Yxd=Fs{O3uHHUi)i_Hr073b+SNC*iEzQHYwe~NxY7~`~(j#9dGV5YQq&5^4PDfR(pcS3oj!vvYH7!Rqtw0Axd}JE`
zY0nt>^lh~$%V}&H}Is5P`Xi~tJ8C+k6vBZto
z1m~e55k3d<>9zPS@QNMUKB=QH`*{pEXJGozSOz|E@FP16LnlDm)Nv|&P^P}}o8W;b
zR|datXh!Mo=4*sYH1#UM%g3SOYr5owIFy?X2NE__yn=W4um{(dbqXl>{7{Nsn>
z3*%
zdc?l+b2a5%EodzwxQXTXubl;pZa`M-mmOLat)=9ETS;xafyAmGP?X+ENpX~TavSlL
zpTVs?g2?pqh)zEj+)_|&?MaM?(b@=|$kY!brhXXhr%=gF=)}9|bR8o1+C)g&Grt>l@gZRAPR&1FQa60
z%La_=|Do{o+w)oY+=D3;a6NSGhct%S0(=};Z!dwo;{lgoyh}sDYT#5%F@;%nxO?S?
zz?5*JVLWjkrr(i$2Mvssz?tN~l(Q8ey@(JmLxeb&{KEg^AHVLF9=5kUzoMiYLt8kw
z$yf1Ko{HY$5~A97pQSZ=iSmm6D-o
z?%mz{{qFg`^AU7yChTn>-?$oo+24|?|AtvXQbf=YY4exk<5Vn%$`$se&`!l0pmiQS
z*hF^s%|yN1hSRld^p`7A6XH7Hr-pBvD)|8D?A2`C8Lj!(N5lWdOnVupUghONQS!VF
ze3{|2D|tUlhsW(X_*2ZB|FfNgz@G!}%3FWh$pBx&)O}1Q+knqtI-4(--99Q=Oc!xw
z-71Y;76?l
z4SzFWoHCSKg;RYo-dQ(|7y(H>deoYb)YQty@d5PaJ<*2mJrX|9(n*h%k3qZN
zrRPWKqJbX*mm)PErOZ>9g7l7A{yJX+J}w`!lX4ws1FoC``H0y8{E7W3wS%J*U`9ah
zm;;})tAS68e2j|-Ga-pw7pFl$;)`co4>AA@>~Ept>;DmcZ~KAhrDFrdPg{*5?R!M;
ze1pv1+lewqPHZ9=MWoL963(St;p}fwIsaTzZfHg_oD@3SMrQAK=-YS^nKy1C|K6iS
z$9JG}o#wfmWDk(yk-u^)hDJY%-6LD1Cd9ELA(Jg1NQyO|!4&Ua4t!H~$E;vIaDfdVXWMkA?U;1f5$Z8
z6Gs1NzSjnsn`YtbdmH!)CiPDkJG-r%UW?SiO`CueN=Uy_WcM}ew!gVI{HHB@qo+HM
z4cAf>KBz3^pjsYeu;F@ww%?iFA4w63B9wmythfsl4fg$ga+bWN
zC+zFF4f$sDbTVkA?pjR2`E)kFyA$}N6_IXvYl?;{0Iy=|XKu8=mpVO|{xH|r^IRAk
zyMVs~uEM0=3a4oIr&DG;pd6?IDwm(B=HGjZbIawIIA2{jPvMNRwp?D52`ll>`V#32
z?g6iQxIlfxriKt4BWPbs?$Cb`biHbY!ewObt}-)UIb|p(h2zZwzZR9M!zn)pQZxlZ^M4cp#kLAJlz%A%=5=D>;POp3bw06PzhVaR|9*Z74ctm$$Mm>((53ZRy0!_1oM=KhT$nIA(d7{(ofv!e)Eri&;9ZT>L_!a;z4>Q2ia_ZQ+Yn+7q7;xT?I~g@%Py_
z5R7_vl52dBuyX_CJJC_bq-Z5xnh}6_wk$myyDJxUl9yj74}QvwevDN@#w#C@hL#R;
z>$Zk#ZhauUPutoWpwG%jTlR
z=dokY;hD~*z{?X1iLk!zm9d}(>Tecwt>
zKt_|03c&s0ZSIX%e$@H;vc+m)+AsdVY#uV%JZMNQy#fF1n{jJD4z6z^{URcw6zCvB
z*!?nL*G8hgy+nhJ=*(dVdm+pe7=apEqp~709(fo|Lh`}LXm3375ewLXX5IbVmgvXd
zeI$Iuo(Kc>V4CUj0k8~M!QAXglEdWwADJN+stVw;QxFh<4JEMOYk-eV@B>cSbLy38
z*zR+HMfQD~uJbvA83Ag+e4{sAOqPHs;EE}}9;rm|(vF#4d$zF9O36GMbeBR3uw%bu
z*g1tka3yfI4ZQtn+E4K`{hgQ*_+T2gL1F3~Qn4ghOLf#-}o
ztCAxjU{pT-&yLTR--3muM+f`ii
zA@U&zf(VERh#&~UtiYY*=a2J@Zvze1VJcK0f}s&?!VZecQ&@_mlw`g)n&d~R_^1ayy0;R*D=BUP%}WKP>zev
zwGp&FOVIKd(ea(85n+@;xs@od$~}k3hsj5Cjnr5fDKT1QC!^6OkYxBHsRHde?1@
zUR8?SeoEDs`D$@RnF-)YNJtnZ1VGtocXgJiZ;$Eq(f&Ka_TLhAtVQ>|1z{eg6v|(K
zauiC%H6jIzO}Pr19wO>mZ$?PQC?7Fn83}Q0c}ig%A
zUo{-~=L0iC*4X60v4Y{^c(thVrKpMz;gr{-%FaZ2^Gy1cTLDfPQTuZQhaUzVj9WgE
zw|j1pnh*^^0LKU5%|_kx;`VU$>R&~_Y42swibmW)e$f6d#pZ$_%q64-L=Xf)1Z2wA
z=UE9UOGro=pz9ZN#y{TR-gMao&eipc)#92;+>~bm`AmMif}l}D1?Y_0QUu38CHaU+
zdEhFunjnO}0m64%b=xbuqV@N$34hXbls0?UET+aI7LVkphscK@2qGXNAc7zWvle%n
z)~jv69b(e5;^5ou?I-i>7QJ!DKD|jR+QSfE!w1r3O8K7YC8$YcQN54ps1XI|E;z%B
za$S?kHO@XDqus8Q8S%*EptVcuJ%{v;wXa2M?tUWt!6VN_zv}HDn$aq*^@t12CFM#G
zgt>~OUyZe$jziN?J-EMFuWfiITKmFQy>HJU-NA4ptaz5I48!SG
zLxuT*AP9mW2!b#dP%~sZ94kW}CKanJ77ldq)XVxjN
zvfMNU9Fl@5l8-Qg{tUEs>0tkR`t5D+girr^qu%gl6Wt6K+~*mt^@znI9`T8gQ4c{7
z<~EXoB?y8b0y6E};$YIkViEBZKYe?91Vn#uo?7v#Rn8w>c#gWPevw*MSEFjH%BfEK
zq*9(K3U^fTR4Md{k-y@^*?YA%OAwku_*_6RkmY!LukJqFs+)En)LWn35^idEhy97|
zj~E`!iRB|_Wkke75ClO4L=XgFPUFp>ZPAGUJ+uLP3Nv!xCzcf8HSE)e8uo<;fG6q~
zvFP$koMq=PRrO03v81lXsh?k^7gv<2Gb_rNpY~O{%r{aJcQALHM6YyhMl^!ZEV(=k
z=5!{LrKdlmTaWdt){bM*;pTQ)_BQIKS9V2>wxB$3g-J1T#3RpenpHB@O2k7D1VIo4
zK@b6%VI)N)N(A#>LO|lh15{HRN1N71?Z7s`t*Z&sXUr$PaGpvps8Q)fwW_A7oQkS)
zs;kSX^?k}c2Tv*GYOTXCBFN<#>>H%JZ;<1CgABIy=-#elI@8{xGwnTOI(kPm2TV3r
zOo~PkBN8z-=@$V7EM><441VIo4K@bF?1O9
- Snapcast
-
+
Copyright © 2014 - 2016 BadAix
Author: Johannes Pohl and contributors
From 8dd594e0d6685a43950af96c0622d3c43cbbe83e Mon Sep 17 00:00:00 2001
From: Johannes Pohl
Date: Sat, 22 Oct 2016 12:48:11 +0200
Subject: [PATCH 22/24] Update build.md
---
doc/build.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/doc/build.md b/doc/build.md
index 5e42421f..6be8eb96 100644
--- a/doc/build.md
+++ b/doc/build.md
@@ -118,12 +118,24 @@ $ brew install flac libvorbis
$ cd /client
$ make TARGET=MACOS
+Install Snapclient
+
+ $ sudo make install
+
+This will copy the client binary to `/usr/local/bin` and create a Launch Agent to start the client as a daemon.
+
###Build Snapserver
`cd` into the Snapserver src-root directory:
$ cd /server
$ make TARGET=MACOS
+Install Snapserver
+
+ $ sudo make install
+
+This will copy the server binary to `/usr/local/bin` and create a Launch Agent to start the server as a daemon.
+
##Android (Cross compile)
Cross compilation for Android is done with the [Android NDK](http://developer.android.com/tools/sdk/ndk/index.html) on a Linux host machine.
From f8671950517164dddd99f0c9ca2f059080384739 Mon Sep 17 00:00:00 2001
From: badaix
Date: Sat, 22 Oct 2016 12:52:43 +0200
Subject: [PATCH 23/24] bump version to 0.9.0
---
android/Snapcast/build.gradle | 4 ++--
client/Makefile | 2 +-
client/debian/changelog | 15 +++++++++++++++
openWrt/Makefile.openwrt | 2 +-
server/Makefile | 2 +-
server/debian/changelog | 15 +++++++++++++++
6 files changed, 35 insertions(+), 5 deletions(-)
diff --git a/android/Snapcast/build.gradle b/android/Snapcast/build.gradle
index fb23b041..2f2cd177 100644
--- a/android/Snapcast/build.gradle
+++ b/android/Snapcast/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "de.badaix.snapcast"
minSdkVersion 16
targetSdkVersion 23
- versionCode 7
- versionName "0.8.0"
+ versionCode 900
+ versionName "0.9.0"
multiDexEnabled true
}
buildTypes {
diff --git a/client/Makefile b/client/Makefile
index b7181ab9..4664f484 100644
--- a/client/Makefile
+++ b/client/Makefile
@@ -1,4 +1,4 @@
-VERSION = 0.8.0
+VERSION = 0.9.0
TARGET = snapclient
SHELL = /bin/bash
diff --git a/client/debian/changelog b/client/debian/changelog
index 8ff58bcf..c292699f 100644
--- a/client/debian/changelog
+++ b/client/debian/changelog
@@ -1,3 +1,18 @@
+snapclient (0.9.0) unstable; urgency=low
+
+ * Features
+ -Added (experimental) support for macOS (make TARGET=MACOS)
+ * Bugfixes
+ -Android client: Fixed crash on Nougat (Issue #97)
+ -Fixed FreeBSD compile error for Snapserver (Issue #107)
+ -Snapserver randomly dropped JSON control messages
+ -Long command line options (like --sampleformat)
+ didn't work on some systems (Issue #103)
+ * General
+ -Updated Android NDK to revision 13
+
+ -- Johannes Pohl Sat, 22 Oct 2016 00:13:37 +0200
+
snapclient (0.8.0) unstable; urgency=low
* Features
diff --git a/openWrt/Makefile.openwrt b/openWrt/Makefile.openwrt
index a28c68cf..af0750c3 100755
--- a/openWrt/Makefile.openwrt
+++ b/openWrt/Makefile.openwrt
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/target.mk
PKG_NAME := snapcast
-PKG_VERSION := 0.8.0
+PKG_VERSION := 0.9.0
PKG_RELEASE := $(PKG_SOURCE_VERSION)
PKG_USE_MIPS16 := 0
diff --git a/server/Makefile b/server/Makefile
index bf514b9d..e3cf3fdb 100644
--- a/server/Makefile
+++ b/server/Makefile
@@ -1,4 +1,4 @@
-VERSION = 0.8.0
+VERSION = 0.9.0
TARGET = snapserver
SHELL = /bin/bash
diff --git a/server/debian/changelog b/server/debian/changelog
index 87a1350c..0cfa53b6 100644
--- a/server/debian/changelog
+++ b/server/debian/changelog
@@ -1,3 +1,18 @@
+snapserver (0.9.0) unstable; urgency=low
+
+ * Features
+ -Added (experimental) support for macOS (make TARGET=MACOS)
+ * Bugfixes
+ -Android client: Fixed crash on Nougat (Issue #97)
+ -Fixed FreeBSD compile error for Snapserver (Issue #107)
+ -Snapserver randomly dropped JSON control messages
+ -Long command line options (like --sampleformat)
+ didn't work on some systems (Issue #103)
+ * General
+ -Updated Android NDK to revision 13
+
+ -- Johannes Pohl Sat, 22 Oct 2016 00:13:37 +0200
+
snapserver (0.8.0) unstable; urgency=low
* Features
From accb15c98f2ff713d185298b859ac245c93604ca Mon Sep 17 00:00:00 2001
From: badaix
Date: Sat, 22 Oct 2016 14:09:42 +0200
Subject: [PATCH 24/24] android binaries for 0.9.0
---
.../main/assets/bin/armeabi-v7a/snapclient | Bin 829244 -> 829244 bytes
.../src/main/assets/bin/armeabi/snapclient | Bin 837428 -> 837428 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
diff --git a/android/Snapcast/src/main/assets/bin/armeabi-v7a/snapclient b/android/Snapcast/src/main/assets/bin/armeabi-v7a/snapclient
index 0b5b5580e1f5f831c5671f60a193ba5010e8e79f..1d48baa7d8e4592af112c68f37ff33444d69a61d 100755
GIT binary patch
delta 166166
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