mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-22 05:26:17 +02:00
configuration is stored in file snapserver.conf
This commit is contained in:
parent
fa508eafba
commit
72bd17cb20
11 changed files with 266 additions and 89 deletions
|
@ -4,7 +4,7 @@
|
|||
<title>Snapcast Interface</title>
|
||||
Taken from <a href="https://github.com/derglaus/snapcast-websockets-ui">derglaus/snapcast-websockets-ui</a> for testing purposes
|
||||
<script>
|
||||
var connection = new WebSocket('ws://127.0.0.1:8080/jsonrpc');
|
||||
var connection = new WebSocket('ws://127.0.0.1:1780/jsonrpc');
|
||||
var server;
|
||||
|
||||
connection.onmessage = function (e) {
|
||||
|
|
|
@ -32,8 +32,9 @@ using namespace std;
|
|||
using json = nlohmann::json;
|
||||
|
||||
|
||||
ControlServer::ControlServer(boost::asio::io_context* io_context, size_t port, ControlMessageReceiver* controlMessageReceiver)
|
||||
: io_context_(io_context), port_(port), controlMessageReceiver_(controlMessageReceiver)
|
||||
ControlServer::ControlServer(boost::asio::io_context* io_context, const ServerSettings::TcpSettings& tcp_settings,
|
||||
const ServerSettings::HttpSettings& http_settings, ControlMessageReceiver* controlMessageReceiver)
|
||||
: io_context_(io_context), controlMessageReceiver_(controlMessageReceiver), tcp_settings_(tcp_settings), http_settings_(http_settings)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,7 @@ void ControlServer::startAccept()
|
|||
|
||||
auto accept_handler_http = [this](error_code ec, tcp::socket socket) {
|
||||
if (!ec)
|
||||
handleAccept<ControlSessionHttp>(std::move(socket));
|
||||
handleAccept<ControlSessionHttp>(std::move(socket), http_settings_);
|
||||
else
|
||||
LOG(ERROR) << "Error while accepting socket connection: " << ec.message() << "\n";
|
||||
};
|
||||
|
@ -114,8 +115,8 @@ void ControlServer::startAccept()
|
|||
}
|
||||
|
||||
|
||||
template <typename SessionType>
|
||||
void ControlServer::handleAccept(tcp::socket socket)
|
||||
template <typename SessionType, typename... Args>
|
||||
void ControlServer::handleAccept(tcp::socket socket, Args&&... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -126,7 +127,7 @@ void ControlServer::handleAccept(tcp::socket socket)
|
|||
setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
// socket->set_option(boost::asio::ip::tcp::no_delay(false));
|
||||
SLOG(NOTICE) << "ControlServer::NewConnection: " << socket.remote_endpoint().address().to_string() << endl;
|
||||
shared_ptr<SessionType> session = make_shared<SessionType>(this, std::move(socket));
|
||||
shared_ptr<SessionType> session = make_shared<SessionType>(this, std::move(socket), std::forward<Args>(args)...);
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> mlock(session_mutex_);
|
||||
session->start();
|
||||
|
@ -179,10 +180,10 @@ std::pair<acceptor_ptr, acceptor_ptr> ControlServer::createAcceptors(size_t port
|
|||
|
||||
void ControlServer::start()
|
||||
{
|
||||
// TODO: should be possible to be disabled
|
||||
acceptor_tcp_ = createAcceptors(port_);
|
||||
// TODO: make port configurable, should be possible to be disabled
|
||||
acceptor_http_ = createAcceptors(8080);
|
||||
if (tcp_settings_.enabled)
|
||||
acceptor_tcp_ = createAcceptors(tcp_settings_.port);
|
||||
if (http_settings_.enabled)
|
||||
acceptor_http_ = createAcceptors(http_settings_.port);
|
||||
startAccept();
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "message/codecHeader.h"
|
||||
#include "message/message.h"
|
||||
#include "message/serverSettings.h"
|
||||
#include "server_settings.hpp"
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
using acceptor_ptr = std::unique_ptr<tcp::acceptor>;
|
||||
|
@ -44,7 +45,8 @@ using acceptor_ptr = std::unique_ptr<tcp::acceptor>;
|
|||
class ControlServer : public ControlMessageReceiver
|
||||
{
|
||||
public:
|
||||
ControlServer(boost::asio::io_context* io_context, size_t port, ControlMessageReceiver* controlMessageReceiver = nullptr);
|
||||
ControlServer(boost::asio::io_context* io_context, const ServerSettings::TcpSettings& tcp_settings, const ServerSettings::HttpSettings& http_settings,
|
||||
ControlMessageReceiver* controlMessageReceiver = nullptr);
|
||||
virtual ~ControlServer();
|
||||
|
||||
void start();
|
||||
|
@ -60,9 +62,8 @@ private:
|
|||
void startAccept();
|
||||
std::pair<acceptor_ptr, acceptor_ptr> createAcceptors(size_t port);
|
||||
|
||||
template <typename SessionType>
|
||||
void handleAccept(tcp::socket socket);
|
||||
// void handleAcceptWs(tcp::socket socket);
|
||||
template <typename SessionType, typename... Args>
|
||||
void handleAccept(tcp::socket socket, Args&&... args);
|
||||
void cleanup();
|
||||
|
||||
mutable std::recursive_mutex session_mutex_;
|
||||
|
@ -72,7 +73,8 @@ private:
|
|||
std::pair<acceptor_ptr, acceptor_ptr> acceptor_http_;
|
||||
|
||||
boost::asio::io_context* io_context_;
|
||||
size_t port_;
|
||||
ServerSettings::TcpSettings tcp_settings_;
|
||||
ServerSettings::HttpSettings http_settings_;
|
||||
ControlMessageReceiver* controlMessageReceiver_;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "common/queue.h"
|
||||
#include "message/message.h"
|
||||
#include "server_settings.hpp"
|
||||
#include <atomic>
|
||||
#include <boost/asio.hpp>
|
||||
#include <condition_variable>
|
||||
|
@ -30,7 +31,6 @@
|
|||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
|
||||
|
|
|
@ -98,7 +98,8 @@ std::string path_cat(boost::beast::string_view base, boost::beast::string_view p
|
|||
}
|
||||
} // namespace
|
||||
|
||||
ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, tcp::socket&& socket) : ControlSession(receiver), socket_(std::move(socket))
|
||||
ControlSessionHttp::ControlSessionHttp(ControlMessageReceiver* receiver, tcp::socket&& socket, const ServerSettings::HttpSettings& settings)
|
||||
: ControlSession(receiver), socket_(std::move(socket)), settings_(settings)
|
||||
{
|
||||
LOG(DEBUG) << "ControlSessionHttp\n";
|
||||
}
|
||||
|
@ -183,10 +184,11 @@ void ControlSessionHttp::handle_request(http::request<Body, http::basic_fields<A
|
|||
if (req.target().empty() || req.target()[0] != '/' || req.target().find("..") != beast::string_view::npos)
|
||||
return send(bad_request("Illegal request-target"));
|
||||
|
||||
// TODO: configurable, enable/disable
|
||||
std::string doc_root = "../control";
|
||||
if (settings_.doc_root.empty())
|
||||
return send(not_found(req.target()));
|
||||
|
||||
// Build the path to the requested file
|
||||
std::string path = path_cat(doc_root, req.target());
|
||||
std::string path = path_cat(settings_.doc_root, req.target());
|
||||
if (req.target().back() == '/')
|
||||
path.append("index.html");
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class ControlSessionHttp : public ControlSession, public std::enable_shared_from
|
|||
{
|
||||
public:
|
||||
/// ctor. Received message from the client are passed to MessageReceiver
|
||||
ControlSessionHttp(ControlMessageReceiver* receiver, tcp::socket&& socket);
|
||||
ControlSessionHttp(ControlMessageReceiver* receiver, tcp::socket&& socket, const ServerSettings::HttpSettings& settings);
|
||||
~ControlSessionHttp() override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
|
@ -71,6 +71,7 @@ protected:
|
|||
protected:
|
||||
tcp::socket socket_;
|
||||
beast::flat_buffer buffer_;
|
||||
ServerSettings::HttpSettings settings_;
|
||||
};
|
||||
|
||||
|
||||
|
|
63
server/server_settings.hpp
Normal file
63
server/server_settings.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/***
|
||||
This file is part of snapcast
|
||||
Copyright (C) 2014-2019 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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#ifndef SERVER_SETTINGS_HPP
|
||||
#define SERVER_SETTINGS_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct ServerSettings
|
||||
{
|
||||
struct HttpSettings
|
||||
{
|
||||
bool enabled{true};
|
||||
size_t port{1780};
|
||||
std::string doc_root{""};
|
||||
};
|
||||
|
||||
struct TcpSettings
|
||||
{
|
||||
bool enabled{true};
|
||||
size_t port{1705};
|
||||
};
|
||||
|
||||
struct StreamSettings
|
||||
{
|
||||
size_t port{1704};
|
||||
std::vector<std::string> pcmStreams;
|
||||
std::string codec{"flac"};
|
||||
int32_t bufferMs{1000};
|
||||
std::string sampleFormat{"48000:16:2"};
|
||||
size_t streamReadMs{20};
|
||||
bool sendAudioToMutedClients{false};
|
||||
};
|
||||
|
||||
struct LoggingSettings
|
||||
{
|
||||
bool debug{false};
|
||||
std::string debug_logfile{""};
|
||||
};
|
||||
|
||||
HttpSettings http;
|
||||
TcpSettings tcp;
|
||||
StreamSettings stream;
|
||||
LoggingSettings logging;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -20,7 +20,7 @@
|
|||
#include <memory>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "popl.hpp"
|
||||
#include "../externals/popl/include/popl.hpp"
|
||||
#ifdef HAS_DAEMON
|
||||
#include "common/daemon.h"
|
||||
#endif
|
||||
|
@ -31,6 +31,7 @@
|
|||
#include "common/utils/string_utils.h"
|
||||
#include "encoder/encoderFactory.h"
|
||||
#include "message/message.h"
|
||||
#include "server_settings.hpp"
|
||||
#include "streamServer.h"
|
||||
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
|
||||
#include "publishZeroConf/publishmDNS.h"
|
||||
|
@ -55,35 +56,57 @@ int main(int argc, char* argv[])
|
|||
int exitcode = EXIT_SUCCESS;
|
||||
try
|
||||
{
|
||||
StreamServerSettings settings;
|
||||
ServerSettings settings;
|
||||
std::string pcmStream = "pipe:///tmp/snapfifo?name=default";
|
||||
std::string config_file = "/etc/snapserver.conf";
|
||||
|
||||
OptionParser op("Allowed options");
|
||||
auto helpSwitch = op.add<Switch>("h", "help", "Produce help message");
|
||||
auto groffSwitch = op.add<Switch, Attribute::hidden>("", "groff", "produce groff message");
|
||||
auto debugOption = op.add<Implicit<string>, Attribute::hidden>("", "debug", "enable debug logging", "");
|
||||
auto versionSwitch = op.add<Switch>("v", "version", "Show version number");
|
||||
op.add<Value<size_t>>("p", "port", "Server port", settings.port, &settings.port);
|
||||
op.add<Value<size_t>>("", "controlPort", "Remote control port", settings.controlPort, &settings.controlPort);
|
||||
auto streamValue = op.add<Value<string>>(
|
||||
"s", "stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
|
||||
&pcmStream);
|
||||
|
||||
op.add<Value<string>>("", "sampleformat", "Default sample format", settings.sampleFormat, &settings.sampleFormat);
|
||||
op.add<Value<string>>("c", "codec", "Default transport codec\n(flac|ogg|pcm)[:options]\nType codec:? to get codec specific options", settings.codec,
|
||||
&settings.codec);
|
||||
op.add<Value<size_t>>("", "streamBuffer", "Default stream read buffer [ms]", settings.streamReadMs, &settings.streamReadMs);
|
||||
op.add<Value<int>>("b", "buffer", "Buffer [ms]", settings.bufferMs, &settings.bufferMs);
|
||||
op.add<Switch>("", "sendToMuted", "Send audio to muted clients", &settings.sendAudioToMutedClients);
|
||||
#ifdef HAS_DAEMON
|
||||
int processPriority(0);
|
||||
auto daemonOption = op.add<Implicit<int>>("d", "daemon", "Daemonize\noptional process priority [-20..19]", 0, &processPriority);
|
||||
auto userValue = op.add<Value<string>>("", "user", "the user[:group] to run snapserver as when daemonized", "");
|
||||
#endif
|
||||
|
||||
op.add<Value<string>>("c", "config", "path to the configuration file", config_file, &config_file);
|
||||
|
||||
// debug settings
|
||||
OptionParser conf("");
|
||||
conf.add<Switch>("", "logging.debug", "enable debug logging", &settings.logging.debug);
|
||||
conf.add<Value<string>>("", "logging.debug_logfile", "log file name for the debug logs (debug must be enabled)", settings.logging.debug_logfile,
|
||||
&settings.logging.debug_logfile);
|
||||
|
||||
// stream settings
|
||||
conf.add<Value<size_t>>("p", "stream.port", "Server port", settings.stream.port, &settings.stream.port);
|
||||
conf.add<Value<size_t>>("", "stream.controlPort", "Remote control port", settings.tcp.port, &settings.tcp.port);
|
||||
auto streamValue = conf.add<Value<string>>(
|
||||
"s", "stream.stream", "URI of the PCM input stream.\nFormat: TYPE://host/path?name=NAME\n[&codec=CODEC]\n[&sampleformat=SAMPLEFORMAT]", pcmStream,
|
||||
&pcmStream);
|
||||
|
||||
conf.add<Value<string>>("", "stream.sampleformat", "Default sample format", settings.stream.sampleFormat, &settings.stream.sampleFormat);
|
||||
conf.add<Value<string>>("c", "stream.codec", "Default transport codec\n(flac|ogg|pcm)[:options]\nType codec:? to get codec specific options",
|
||||
settings.stream.codec, &settings.stream.codec);
|
||||
conf.add<Value<size_t>>("", "stream.streamBuffer", "Default stream read buffer [ms]", settings.stream.streamReadMs, &settings.stream.streamReadMs);
|
||||
conf.add<Value<int>>("b", "stream.buffer", "Buffer [ms]", settings.stream.bufferMs, &settings.stream.bufferMs);
|
||||
conf.add<Switch>("", "stream.sendToMuted", "Send audio to muted clients", &settings.stream.sendAudioToMutedClients);
|
||||
|
||||
// HTTP RPC settings
|
||||
conf.add<Switch>("", "http.enabled", "enable HTTP Json RPC (HTTP POST and websockets)", &settings.http.enabled);
|
||||
conf.add<Value<size_t>>("", "http.port", "which port the server should listen to", settings.http.port, &settings.http.port);
|
||||
conf.add<Value<string>>("", "http.doc_root", "serve a website from the doc_root location", settings.http.doc_root, &settings.http.doc_root);
|
||||
|
||||
// TCP RPC settings
|
||||
conf.add<Switch>("", "tcp.enabled", "enable TCP Json RPC)", &settings.tcp.enabled);
|
||||
conf.add<Value<size_t>>("", "tcp.port", "which port the server should listen to", settings.tcp.port, &settings.tcp.port);
|
||||
|
||||
// TODO: Should be possible to override settings on command line
|
||||
|
||||
try
|
||||
{
|
||||
op.parse(argc, argv);
|
||||
conf.parse(config_file);
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
|
@ -116,34 +139,25 @@ int main(int argc, char* argv[])
|
|||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!streamValue->is_set())
|
||||
settings.pcmStreams.push_back(streamValue->value());
|
||||
|
||||
for (size_t n = 0; n < streamValue->count(); ++n)
|
||||
{
|
||||
cout << streamValue->value(n) << "\n";
|
||||
settings.pcmStreams.push_back(streamValue->value(n));
|
||||
}
|
||||
|
||||
if (settings.codec.find(":?") != string::npos)
|
||||
if (settings.stream.codec.find(":?") != string::npos)
|
||||
{
|
||||
EncoderFactory encoderFactory;
|
||||
std::unique_ptr<Encoder> encoder(encoderFactory.createEncoder(settings.codec));
|
||||
std::unique_ptr<Encoder> encoder(encoderFactory.createEncoder(settings.stream.codec));
|
||||
if (encoder)
|
||||
{
|
||||
cout << "Options for codec \"" << encoder->name() << "\":\n"
|
||||
<< " " << encoder->getAvailableOptions() << "\n"
|
||||
<< " Default: \"" << encoder->getDefaultOptions() << "\"\n";
|
||||
}
|
||||
return 1;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
AixLog::Log::init<AixLog::SinkNative>("snapserver", AixLog::Severity::trace, AixLog::Type::special);
|
||||
if (debugOption->is_set())
|
||||
if (settings.logging.debug)
|
||||
{
|
||||
AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::trace, AixLog::Type::all, "%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
|
||||
if (!debugOption->value().empty())
|
||||
AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, debugOption->value(),
|
||||
if (!settings.logging.debug_logfile.empty())
|
||||
AixLog::Log::instance().add_logsink<AixLog::SinkFile>(AixLog::Severity::trace, AixLog::Type::all, settings.logging.debug_logfile,
|
||||
"%Y-%m-%d %H-%M-%S.#ms [#severity] (#tag_func)");
|
||||
}
|
||||
else
|
||||
|
@ -151,6 +165,14 @@ int main(int argc, char* argv[])
|
|||
AixLog::Log::instance().add_logsink<AixLog::SinkCout>(AixLog::Severity::info, AixLog::Type::all, "%Y-%m-%d %H-%M-%S [#severity]");
|
||||
}
|
||||
|
||||
if (!streamValue->is_set())
|
||||
settings.stream.pcmStreams.push_back(streamValue->value());
|
||||
|
||||
for (size_t n = 0; n < streamValue->count(); ++n)
|
||||
{
|
||||
LOG(INFO) << "Adding stream: " << streamValue->value(n) << "\n";
|
||||
settings.stream.pcmStreams.push_back(streamValue->value(n));
|
||||
}
|
||||
|
||||
signal(SIGHUP, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
@ -194,12 +216,26 @@ int main(int argc, char* argv[])
|
|||
|
||||
#if defined(HAS_AVAHI) || defined(HAS_BONJOUR)
|
||||
PublishZeroConf publishZeroConfg("Snapcast");
|
||||
publishZeroConfg.publish({mDNSService("_snapcast._tcp", settings.port), mDNSService("_snapcast-jsonrpc._tcp", settings.controlPort),
|
||||
mDNSService("_snapcastjsonrpc._tcp", settings.controlPort)});
|
||||
vector<mDNSService> dns_services;
|
||||
dns_services.emplace_back("_snapcast._tcp", settings.stream.port);
|
||||
dns_services.emplace_back("_snapcast-stream._tcp", settings.stream.port);
|
||||
if (settings.tcp.enabled)
|
||||
{
|
||||
dns_services.emplace_back("_snapcast-jsonrpc._tcp", settings.tcp.port);
|
||||
dns_services.emplace_back("_snapcast-tcp._tcp", settings.tcp.port);
|
||||
}
|
||||
if (settings.http.enabled)
|
||||
{
|
||||
dns_services.emplace_back("_snapcast-http._tcp", settings.http.port);
|
||||
}
|
||||
publishZeroConfg.publish(dns_services);
|
||||
#endif
|
||||
|
||||
if (settings.bufferMs < 400)
|
||||
settings.bufferMs = 400;
|
||||
if (settings.stream.bufferMs < 400)
|
||||
{
|
||||
LOG(WARNING) << "Buffer is less than 400ms, changing to 400ms\n";
|
||||
settings.stream.bufferMs = 400;
|
||||
}
|
||||
|
||||
boost::asio::io_context io_context;
|
||||
std::unique_ptr<StreamServer> streamServer(new StreamServer(&io_context, settings));
|
||||
|
|
87
server/snapserver.conf
Normal file
87
server/snapserver.conf
Normal file
|
@ -0,0 +1,87 @@
|
|||
##################################
|
||||
### ###
|
||||
### Snapserver config file ###
|
||||
### ###
|
||||
##################################
|
||||
|
||||
# default values are commented
|
||||
# to change them, just uncomment
|
||||
|
||||
# HTTP RPC ####################################################################
|
||||
#
|
||||
[http]
|
||||
# enable HTTP Json RPC (HTTP POST and websockets)
|
||||
enabled = true
|
||||
|
||||
# address to listen on
|
||||
# TODO: not implemented yet
|
||||
bind_to_address = 127.0.0.1
|
||||
|
||||
# which port the server should listen to
|
||||
port = 1780
|
||||
|
||||
# serve a website from the doc_root location
|
||||
doc_root = /home/johannes/Develop/snapcast/control
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# TCP RPC #####################################################################
|
||||
#
|
||||
[tcp]
|
||||
# enable TCP Json RPC
|
||||
enabled = true_
|
||||
|
||||
# address to listen on
|
||||
# TODO: not implemented yet
|
||||
bind_to_address = 127.0.0.1
|
||||
|
||||
# which port the server should listen to
|
||||
port = 1705
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# Stream settings #############################################################
|
||||
#
|
||||
[stream]
|
||||
# address to listen on
|
||||
# TODO: not implemented yet
|
||||
#bind_to_address = 0.0.0.0
|
||||
|
||||
# which port the server should listen to
|
||||
#port = 1704
|
||||
|
||||
# stream URI of the PCM input stream, can be configured multiple times
|
||||
# Format: TYPE://host/path?name=NAME[&codec=CODEC][&sampleformat=SAMPLEFORMAT]
|
||||
stream = pipe:///tmp/snapfifo?name=default
|
||||
stream = pipe:///tmp/snapfifo2?name=default2
|
||||
|
||||
# Default sample format
|
||||
#sampleformat = 48000:16:2
|
||||
|
||||
# Default transport codec
|
||||
# (flac|ogg|pcm)[:options]
|
||||
# Type codec:? to get codec specific options
|
||||
#codec = flac
|
||||
|
||||
# Default stream read buffer [ms]
|
||||
#streamBuffer = 20
|
||||
|
||||
# Buffer [ms]
|
||||
#buffer = 1000
|
||||
|
||||
# Send audio to muted clients
|
||||
#sendToMuted = false
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
# Logging options #############################################################
|
||||
#
|
||||
[logging]
|
||||
|
||||
# enable debug logging
|
||||
#debug = false
|
||||
|
||||
# log file name for the debug logs (debug must be enabled)
|
||||
#debug_logfile =
|
||||
#
|
||||
###############################################################################
|
|
@ -29,8 +29,8 @@ using namespace std;
|
|||
using json = nlohmann::json;
|
||||
|
||||
|
||||
StreamServer::StreamServer(boost::asio::io_context* io_context, const StreamServerSettings& streamServerSettings)
|
||||
: io_context_(io_context), acceptor_v4_(nullptr), acceptor_v6_(nullptr), settings_(streamServerSettings)
|
||||
StreamServer::StreamServer(boost::asio::io_context* io_context, const ServerSettings& serverSettings)
|
||||
: io_context_(io_context), acceptor_v4_(nullptr), acceptor_v6_(nullptr), settings_(serverSettings)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ void StreamServer::onChunkRead(const PcmStream* pcmStream, msg::PcmChunk* chunk,
|
|||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||
for (auto s : sessions_)
|
||||
{
|
||||
if (!settings_.sendAudioToMutedClients)
|
||||
if (!settings_.stream.sendAudioToMutedClients)
|
||||
{
|
||||
GroupPtr group = Config::instance().getGroupFromClient(s->clientId);
|
||||
if (group)
|
||||
|
@ -195,9 +195,9 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
|
|||
int latency = request->params().get("latency");
|
||||
if (latency < -10000)
|
||||
latency = -10000;
|
||||
else if (latency > settings_.bufferMs)
|
||||
latency = settings_.bufferMs;
|
||||
clientInfo->config.latency = latency; //, -10000, settings_.bufferMs);
|
||||
else if (latency > settings_.stream.bufferMs)
|
||||
latency = settings_.stream.bufferMs;
|
||||
clientInfo->config.latency = latency; //, -10000, settings_.stream.bufferMs);
|
||||
result["latency"] = clientInfo->config.latency;
|
||||
notification.reset(
|
||||
new jsonrpcpp::Notification("Client.OnLatencyChanged", jsonrpcpp::Parameter("id", clientInfo->id, "latency", clientInfo->config.latency)));
|
||||
|
@ -223,7 +223,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
|
|||
if (session != nullptr)
|
||||
{
|
||||
auto serverSettings = make_shared<msg::ServerSettings>();
|
||||
serverSettings->setBufferMs(settings_.bufferMs);
|
||||
serverSettings->setBufferMs(settings_.stream.bufferMs);
|
||||
serverSettings->setVolume(clientInfo->config.volume.percent);
|
||||
GroupPtr group = Config::instance().getGroupFromClient(clientInfo);
|
||||
serverSettings->setMuted(clientInfo->config.volume.muted || group->muted);
|
||||
|
@ -274,7 +274,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp
|
|||
if (session != nullptr)
|
||||
{
|
||||
auto serverSettings = make_shared<msg::ServerSettings>();
|
||||
serverSettings->setBufferMs(settings_.bufferMs);
|
||||
serverSettings->setBufferMs(settings_.stream.bufferMs);
|
||||
serverSettings->setVolume(client->config.volume.percent);
|
||||
GroupPtr group = Config::instance().getGroupFromClient(client);
|
||||
serverSettings->setMuted(client->config.volume.muted || group->muted);
|
||||
|
@ -667,7 +667,7 @@ void StreamServer::onMessageReceived(StreamSession* streamSession, const msg::Ba
|
|||
serverSettings->setVolume(client->config.volume.percent);
|
||||
serverSettings->setMuted(client->config.volume.muted || group->muted);
|
||||
serverSettings->setLatency(client->config.latency);
|
||||
serverSettings->setBufferMs(settings_.bufferMs);
|
||||
serverSettings->setBufferMs(settings_.stream.bufferMs);
|
||||
serverSettings->refersTo = helloMsg.id;
|
||||
streamSession->sendAsync(serverSettings);
|
||||
|
||||
|
@ -793,7 +793,7 @@ void StreamServer::handleAccept(socket_ptr socket)
|
|||
SLOG(NOTICE) << "StreamServer::NewConnection: " << socket->remote_endpoint().address().to_string() << endl;
|
||||
shared_ptr<StreamSession> session = make_shared<StreamSession>(this, socket);
|
||||
|
||||
session->setBufferMs(settings_.bufferMs);
|
||||
session->setBufferMs(settings_.stream.bufferMs);
|
||||
session->start();
|
||||
|
||||
std::lock_guard<std::recursive_mutex> mlock(sessionsMutex_);
|
||||
|
@ -811,12 +811,12 @@ void StreamServer::start()
|
|||
{
|
||||
try
|
||||
{
|
||||
controlServer_.reset(new ControlServer(io_context_, settings_.controlPort, this));
|
||||
controlServer_.reset(new ControlServer(io_context_, settings_.tcp, settings_.http, this));
|
||||
controlServer_->start();
|
||||
|
||||
streamManager_.reset(new StreamManager(this, settings_.sampleFormat, settings_.codec, settings_.streamReadMs));
|
||||
streamManager_.reset(new StreamManager(this, settings_.stream.sampleFormat, settings_.stream.codec, settings_.stream.streamReadMs));
|
||||
// throw SnapException("xxx");
|
||||
for (const auto& streamUri : settings_.pcmStreams)
|
||||
for (const auto& streamUri : settings_.stream.pcmStreams)
|
||||
{
|
||||
PcmStreamPtr stream = streamManager_->addStream(streamUri);
|
||||
if (stream)
|
||||
|
@ -825,7 +825,7 @@ void StreamServer::start()
|
|||
streamManager_->start();
|
||||
|
||||
bool is_v6_only(true);
|
||||
tcp::endpoint endpoint_v6(tcp::v6(), settings_.port);
|
||||
tcp::endpoint endpoint_v6(tcp::v6(), settings_.stream.port);
|
||||
try
|
||||
{
|
||||
acceptor_v6_ = make_shared<tcp::acceptor>(*io_context_, endpoint_v6);
|
||||
|
@ -843,7 +843,7 @@ void StreamServer::start()
|
|||
|
||||
if (!acceptor_v6_ || is_v6_only)
|
||||
{
|
||||
tcp::endpoint endpoint_v4(tcp::v4(), settings_.port);
|
||||
tcp::endpoint endpoint_v4(tcp::v4(), settings_.stream.port);
|
||||
try
|
||||
{
|
||||
acceptor_v4_ = make_shared<tcp::acceptor>(*io_context_, endpoint_v4);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "message/codecHeader.h"
|
||||
#include "message/message.h"
|
||||
#include "message/serverSettings.h"
|
||||
#include "server_settings.hpp"
|
||||
#include "streamSession.h"
|
||||
#include "streamreader/streamManager.h"
|
||||
|
||||
|
@ -42,22 +43,6 @@ using boost::asio::ip::tcp;
|
|||
typedef std::shared_ptr<tcp::socket> socket_ptr;
|
||||
typedef std::shared_ptr<StreamSession> session_ptr;
|
||||
|
||||
struct StreamServerSettings
|
||||
{
|
||||
StreamServerSettings()
|
||||
: port(1704), controlPort(1705), codec("flac"), bufferMs(1000), sampleFormat("48000:16:2"), streamReadMs(20), sendAudioToMutedClients(false)
|
||||
{
|
||||
}
|
||||
size_t port;
|
||||
size_t controlPort;
|
||||
std::vector<std::string> pcmStreams;
|
||||
std::string codec;
|
||||
int32_t bufferMs;
|
||||
std::string sampleFormat;
|
||||
size_t streamReadMs;
|
||||
bool sendAudioToMutedClients;
|
||||
};
|
||||
|
||||
|
||||
/// Forwars PCM data to the connected clients
|
||||
/**
|
||||
|
@ -69,7 +54,7 @@ struct StreamServerSettings
|
|||
class StreamServer : public MessageReceiver, ControlMessageReceiver, PcmListener
|
||||
{
|
||||
public:
|
||||
StreamServer(boost::asio::io_context* io_context, const StreamServerSettings& streamServerSettings);
|
||||
StreamServer(boost::asio::io_context* io_context, const ServerSettings& serverSettings);
|
||||
virtual ~StreamServer();
|
||||
|
||||
void start();
|
||||
|
@ -103,7 +88,7 @@ private:
|
|||
std::shared_ptr<tcp::acceptor> acceptor_v4_;
|
||||
std::shared_ptr<tcp::acceptor> acceptor_v6_;
|
||||
|
||||
StreamServerSettings settings_;
|
||||
ServerSettings settings_;
|
||||
Queue<std::shared_ptr<msg::BaseMessage>> messages_;
|
||||
std::unique_ptr<ControlServer> controlServer_;
|
||||
std::unique_ptr<StreamManager> streamManager_;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue