Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions sound/snapcast/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# SPDX-License-Identifier: GPL-2.0-or-later

include $(TOPDIR)/rules.mk

PKG_NAME:=snapcast
PKG_VERSION:=0.28.0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest release is 0.32.3. Why not use that one?

@xabolcs xabolcs Sep 8, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @GeorgeSapkin !

The latest release is 0.32.3. Why not use that one?

It started with 0.29.0 where OpenSSL support introduced and I got problems with it (back in January 2025):

Well in the meantime Snapcast 0.29.0 came out which has HTTPS support, but I'm so noob I don't know how to add those dependencies! 🙈
I mean:

Package snapserver is missing dependencies for the following libraries:
libcrypto.so.3
libssl.so.3

Sure, I could stick with 0.28.0. 🤷

At that point of time I decided to stick with 0.28.0 and deal with this OpenSSL support later with a followup PR where I introduce different flavours: snap*-mini and snap*-full.
And I also want to make the Avahi dependency optional: snapcast/snapos#4

And then, last week @1715173329 suggested how to solve the problem

I found this:

Package snapserver is missing dependencies for the following libraries:
libcrypto.so.3
libssl.so.3

Please add libopenssl to DEPENDS, it should resolve the issue.

And now we are here.

In summary:

  • I'd like to include snapcast before OpenWrt 25.xx branches off (and hopefully backport to 24.10, @hunterzero99 had a success build for once)
  • with that in mind I choose to stick to 0.28.0 and backport compatibility fixes
    • because I don't know how to be a maintainer in openwrt/packages and this would be my first package
  • and after I learn how to deal with those things above, I plan update to latest tagged Snapcast or even to specific develop commit (see talk with @neheb)

If you have time and energy to coordinate me with these problems (disabling the OpenSSL support is on upstream develop, see snapcast/snapcast#1427) I happily go this way in this PR! 👌 🙏

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the summary. I guess if everybody else is OK with this, then I'm OK.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the summary.

Thank you for asking!
Now it's summarized. 🙂

Should I add a few lines about these into the commit?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it wouldn't hurt for future reference.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it wouldn't hurt for future reference.

riscv64 is still building, but here comes my amended commit message!

PKG_RELEASE:=1

PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/badaix/snapcast.git
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
PKG_MIRROR_HASH=288325fc8b134502adb522711c18210794734675684cf5d8eba8a0a82778f6c9

PKG_MAINTAINER:=Szabolcs Hubai <szab.hu@gmail.com>, David Andreoletti <david@andreoletti.net>
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE
PKG_CPE_ID:=cpe:/a:badaix:snapcast

include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk

CMAKE_OPTIONS += -DBUILD_TESTS=OFF

define Package/snapcast/Default
SECTION:=sound
CATEGORY:=Sound
Comment thread
1715173329 marked this conversation as resolved.
TITLE:=Synchronous multiroom audio player
DEPENDS:=+AUDIO_SUPPORT:alsa-lib +libavahi-client +libatomic +libogg +libflac +libopus +boost +libsoxr
URL:=https://github.com/badaix/snapcast
endef

define Package/snapcast/Default/description
Synchronous audio player - Snapcast

Snapcast is a multi-room client-server audio player,
where all clients are time synchronized with the server
to play perfectly synced audio.
It's not a standalone player, but an extension that turns
your existing audio player into a Sonos-like multiroom solution.
Audio is captured by the server and routed to the connected clients.
Several players can feed audio to the server in parallel
and clients can be grouped to play the same audio stream.
One of the most generic ways to use Snapcast is in conjunction
with the Music Player Daemon (MPD) or Mopidy.

endef

define Package/snapserver
$(call Package/snapcast/Default)
TITLE+= (server)
DEPENDS+=+libvorbis
endef

define Package/snapclient
$(call Package/snapcast/Default)
TITLE+= (client)
DEPENDS+=+libvorbisidec
endef

define Package/snapserver/description
$(call Package/snapcast/Default/description)
This package contains the Snapcast server.
endef

define Package/snapclient/description
$(call Package/snapcast/Default/description)
This package contains the Snapcast client.
endef

define Package/snapserver/conffiles
/etc/config/snapserver
/etc/snapserver.conf
endef

define Package/snapclient/conffiles
/etc/config/snapclient
endef

define Package/snapserver/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/snapserver $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/snapserver.init $(1)/etc/init.d/snapserver
$(INSTALL_CONF) $(PKG_BUILD_DIR)/server/etc/snapserver.conf $(1)/etc/snapserver.conf
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/snapserver.conf $(1)/etc/config/snapserver

endef

define Package/snapclient/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/snapclient $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/snapclient.init $(1)/etc/init.d/snapclient
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/snapclient.conf $(1)/etc/config/snapclient
endef

$(eval $(call BuildPackage,snapserver))
$(eval $(call BuildPackage,snapclient))
4 changes: 4 additions & 0 deletions sound/snapcast/files/snapclient.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
config snapclient 'config'
option enabled '0'
option log_sink 'system'
option opts ''
33 changes: 33 additions & 0 deletions sound/snapcast/files/snapclient.init
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/sh /etc/rc.common
# Author: Johannes Pohl <johannes.pohl@badaix.de>
# Co-Author: Szabolcs Hubai <szab.hu@gmail.com>
START=90

USE_PROCD=1

NAME=snapclient
PROG=/usr/bin/$NAME
PID_FILE=/var/run/$NAME.pid

Comment thread
1715173329 marked this conversation as resolved.
start_service()
{
config_load "$NAME"

local enabled
config_get_bool enabled "config" enabled 0
[ "$enabled" -ne "1" ] && logger -t $NAME "Disabled in /etc/config/$NAME" && return 1

local log_sink opts
config_get log_sink "config" log_sink system
config_get opts "config" opts ""

procd_open_instance
procd_set_param command $PROG
procd_append_param command --logsink $log_sink
procd_append_param command $opts
procd_set_param pidfile $PID_FILE
procd_set_param respawn # use the defaults for respawing crashed process
procd_set_param stderr 1
procd_set_param stdout 1
procd_close_instance
}
4 changes: 4 additions & 0 deletions sound/snapcast/files/snapserver.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
config snapserver 'config'
option enabled '0'
option log_sink 'system'
option opts ''
33 changes: 33 additions & 0 deletions sound/snapcast/files/snapserver.init
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/bin/sh /etc/rc.common
# Author: Johannes Pohl <johannes.pohl@badaix.de>
# Co-Author: Szabolcs Hubai <szab.hu@gmail.com>
START=90

USE_PROCD=1

NAME=snapserver
PROG=/usr/bin/$NAME
PID_FILE=/var/run/$NAME.pid

start_service()
{
config_load "$NAME"

local enabled
config_get_bool enabled "config" enabled 0
[ "$enabled" -ne "1" ] && logger -t $NAME "Disabled in /etc/config/$NAME" && return 1

local log_sink opts
config_get log_sink "config" log_sink system
config_get opts "config" opts ""

procd_open_instance
procd_set_param command $PROG
procd_append_param command --logging.sink $log_sink
procd_append_param command $opts
procd_set_param pidfile $PID_FILE
procd_set_param respawn # use the defaults for respawing crashed process
procd_set_param stderr 1
procd_set_param stdout 1
procd_close_instance
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
From 6ada939adf5c4f7e43d0fbe6ea45492b9564cb8d Mon Sep 17 00:00:00 2001
From: badaix <johannes.pohl@badaix.de>
Date: Thu, 19 Dec 2024 22:53:49 +0100
Subject: [PATCH] Fix compilation with boost v1.87.0
Comment thread
1715173329 marked this conversation as resolved.

---
server/control_server.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

--- a/server/control_server.cpp
+++ b/server/control_server.cpp
@@ -161,7 +161,7 @@ void ControlServer::start()
{
LOG(INFO, LOG_TAG) << "Creating TCP acceptor for address: " << address << ", port: " << tcp_settings_.port << "\n";
acceptor_tcp_.emplace_back(make_unique<tcp::acceptor>(boost::asio::make_strand(io_context_.get_executor()),
- tcp::endpoint(boost::asio::ip::address::from_string(address), tcp_settings_.port)));
+ tcp::endpoint(boost::asio::ip::make_address(address), settings_.tcp.port)));
}
catch (const boost::system::system_error& e)
{
@@ -177,7 +177,7 @@ void ControlServer::start()
{
LOG(INFO, LOG_TAG) << "Creating HTTP acceptor for address: " << address << ", port: " << http_settings_.port << "\n";
acceptor_http_.emplace_back(make_unique<tcp::acceptor>(boost::asio::make_strand(io_context_.get_executor()),
- tcp::endpoint(boost::asio::ip::address::from_string(address), http_settings_.port)));
+ tcp::endpoint(boost::asio::ip::make_address(address), settings_.http.port)));
}
catch (const boost::system::system_error& e)
{
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
From b2fd2bf9ef835104a813c40c190d71e3644125d7 Mon Sep 17 00:00:00 2001
From: Rudi Heitbaum <rudi@heitbaum.com>
Date: Thu, 19 Dec 2024 02:23:11 +1100
Subject: [PATCH] use make_address from boost as from_string is deprecated
(#1308)

Since boost 1.87.0 boost::asio::ip::address::from_string is no longer available

ref: https://github.com/boostorg/asio/commit/c0d1cfce7767599c4cf00df36f8017a1073339ae

fixes:
../server/control_server.cpp: In member function 'void ControlServer::start()':
../server/control_server.cpp:164:111: error: 'from_string' is not a member of 'boost::asio::ip::address'
164 | tcp::endpoint(boost::asio::ip::address::from_string(address), tcp_settings_.port)));
| ^~~~~~~~~~~
../server/control_server.cpp:180:112: error: 'from_string' is not a member of 'boost::asio::ip::address'
180 | tcp::endpoint(boost::asio::ip::address::from_string(address), http_settings_.port)));
| ^~~~~~~~~~~
../server/streamreader/tcp_stream.cpp: In constructor 'streamreader::TcpStream::TcpStream(streamreader::PcmStream::Listener*, boost::asio::io_context&, const ServerSettings&, const streamreader::StreamUri&)':
../server/streamreader/tcp_stream.cpp:67:97: error: 'from_string' is not a member of 'boost::asio::ip::address'
67 | acceptor_ = make_unique<tcp::acceptor>(strand_, tcp::endpoint(boost::asio::ip::address::from_string(host_), port_));
| ^~~~~~~~~~~
../server/streamreader/tcp_stream.cpp: In member function 'virtual void streamreader::TcpStream::connect()':
../server/streamreader/tcp_stream.cpp:96:75: error: 'from_string' is not a member of 'boost::asio::ip::address'
96 | boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host_), port_);
| ^~~~~~~~~~~
../server/stream_server.cpp: In member function 'void StreamServer::start()':
../server/stream_server.cpp:234:103: error: 'from_string' is not a member of 'boost::asio::ip::address'
234 | tcp::endpoint(boost::asio::ip::address::from_string(address), settings_.stream.port)));
|
---
server/control_server.cpp | 4 ++--
server/stream_server.cpp | 2 +-
server/streamreader/tcp_stream.cpp | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)

--- a/server/control_server.cpp
+++ b/server/control_server.cpp
@@ -161,7 +161,7 @@ void ControlServer::start()
{
LOG(INFO, LOG_TAG) << "Creating TCP acceptor for address: " << address << ", port: " << tcp_settings_.port << "\n";
acceptor_tcp_.emplace_back(make_unique<tcp::acceptor>(boost::asio::make_strand(io_context_.get_executor()),
- tcp::endpoint(boost::asio::ip::make_address(address), settings_.tcp.port)));
+ tcp::endpoint(boost::asio::ip::make_address(address), tcp_settings_.port)));
}
catch (const boost::system::system_error& e)
{
@@ -177,7 +177,7 @@ void ControlServer::start()
{
LOG(INFO, LOG_TAG) << "Creating HTTP acceptor for address: " << address << ", port: " << http_settings_.port << "\n";
acceptor_http_.emplace_back(make_unique<tcp::acceptor>(boost::asio::make_strand(io_context_.get_executor()),
- tcp::endpoint(boost::asio::ip::make_address(address), settings_.http.port)));
+ tcp::endpoint(boost::asio::ip::make_address(address), http_settings_.port)));
}
catch (const boost::system::system_error& e)
{
--- a/server/stream_server.cpp
+++ b/server/stream_server.cpp
@@ -231,7 +231,7 @@ void StreamServer::start()
{
LOG(INFO, LOG_TAG) << "Creating stream acceptor for address: " << address << ", port: " << settings_.stream.port << "\n";
acceptor_.emplace_back(make_unique<tcp::acceptor>(boost::asio::make_strand(io_context_.get_executor()),
- tcp::endpoint(boost::asio::ip::address::from_string(address), settings_.stream.port)));
+ tcp::endpoint(boost::asio::ip::make_address(address), settings_.stream.port)));
}
catch (const boost::system::system_error& e)
{
--- a/server/streamreader/tcp_stream.cpp
+++ b/server/streamreader/tcp_stream.cpp
@@ -64,7 +64,7 @@ TcpStream::TcpStream(PcmStream::Listener

LOG(INFO, LOG_TAG) << "TcpStream host: " << host_ << ", port: " << port_ << ", is server: " << is_server_ << "\n";
if (is_server_)
- acceptor_ = make_unique<tcp::acceptor>(strand_, tcp::endpoint(boost::asio::ip::address::from_string(host_), port_));
+ acceptor_ = make_unique<tcp::acceptor>(strand_, tcp::endpoint(boost::asio::ip::make_address(host_), port_));
}


@@ -93,7 +93,7 @@ void TcpStream::connect()
else
{
stream_ = make_unique<tcp::socket>(strand_);
- boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host_), port_);
+ boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::make_address(host_), port_);
stream_->async_connect(endpoint,
[this](const boost::system::error_code& ec)
{
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
From 6190041e863968d76b6d16140bba90be6dff848f Mon Sep 17 00:00:00 2001
From: badaix <johannes.pohl@badaix.de>
Date: Thu, 19 Dec 2024 21:36:08 +0100
Subject: [PATCH] Fix compilation with boost v1.87.0

---
client/client_connection.cpp | 5 ++---
server/stream_session_ws.cpp | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)

--- a/client/client_connection.cpp
+++ b/client/client_connection.cpp
@@ -124,10 +124,9 @@ std::string ClientConnection::getMacAddr

void ClientConnection::connect(const ResultHandler& handler)
{
- tcp::resolver::query query(server_.host, cpt::to_string(server_.port), boost::asio::ip::resolver_query_base::numeric_service);
boost::system::error_code ec;
LOG(INFO, LOG_TAG) << "Resolving host IP for: " << server_.host << "\n";
- auto iterator = resolver_.resolve(query, ec);
+ auto iterator = resolver_.resolve(server_.host, cpt::to_string(server_.port), boost::asio::ip::resolver_query_base::numeric_service, ec);
if (ec)
{
LOG(ERROR, LOG_TAG) << "Failed to resolve host '" << server_.host << "', error: " << ec.message() << "\n";
@@ -141,7 +140,7 @@ void ClientConnection::connect(const Res
for (const auto& iter : iterator)
{
LOG(INFO, LOG_TAG) << "Connecting to " << iter.endpoint() << "\n";
- socket_.connect(*iterator, ec);
+ socket_.connect(iter, ec);
if (!ec || (ec == boost::system::errc::interrupted))
{
// We were successful or interrupted, e.g. by sig int
--- a/server/stream_session_ws.cpp
+++ b/server/stream_session_ws.cpp
@@ -114,7 +114,7 @@ void StreamSessionWebsocket::on_read_ws(
return;
}

- auto* data = boost::asio::buffer_cast<char*>(buffer_.data());
+ auto* data = static_cast<char*>(buffer_.data().data());
baseMessage_.deserialize(data);
LOG(DEBUG, LOG_TAG) << "getNextMessage: " << baseMessage_.type << ", size: " << baseMessage_.size << ", id: " << baseMessage_.id
<< ", refers: " << baseMessage_.refersTo << "\n";
Loading
Loading