Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/snapserver: update module to work with snapcast 0.20 #94071

Merged
merged 2 commits into from
Aug 2, 2020
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
166 changes: 121 additions & 45 deletions nixos/modules/services/audio/snapserver.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,42 @@ let
let
os = val:
optionalString (val != null) "${val}";
os' = prefixx: val:
optionalString (val != null) (prefixx + "${val}");
os' = prefix: val:
optionalString (val != null) (prefix + "${val}");
flatten = key: value:
"&${key}=${value}";
in
"-s ${opt.type}://" + os opt.location + "?" + os' "name=" name
+ concatStrings (mapAttrsToList flatten opt.query);
"--stream.stream=\"${opt.type}://" + os opt.location + "?" + os' "name=" name
+ concatStrings (mapAttrsToList flatten opt.query) + "\"";

optionalNull = val: ret:
optional (val != null) ret;

optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
++ ["-p ${toString cfg.port}"]
++ ["--controlPort ${toString cfg.controlPort}"]
++ optionalNull cfg.sampleFormat "--sampleFormat ${cfg.sampleFormat}"
++ optionalNull cfg.codec "-c ${cfg.codec}"
++ optionalNull cfg.streamBuffer "--streamBuffer ${cfg.streamBuffer}"
++ optionalNull cfg.buffer "-b ${cfg.buffer}"
++ optional cfg.sendToMuted "--sendToMuted");
# global options
++ [ "--stream.bind_to_address ${cfg.listenAddress}" ]
++ [ "--stream.port ${toString cfg.port}" ]
++ optionalNull cfg.sampleFormat "--stream.sampleformat ${cfg.sampleFormat}"
++ optionalNull cfg.codec "--stream.codec ${cfg.codec}"
++ optionalNull cfg.streamBuffer "--stream.stream_buffer ${cfg.streamBuffer}"
++ optionalNull cfg.buffer "--stream.buffer ${cfg.buffer}"
++ optional cfg.sendToMuted "--stream.send_to_muted"
# tcp json rpc
++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ]
++ optionals cfg.tcp.enable [
"--tcp.address ${cfg.tcp.listenAddress}"
"--tcp.port ${toString cfg.tcp.port}" ]
# http json rpc
++ [ "--http.enabled ${toString cfg.http.enable}" ]
++ optionals cfg.http.enable [
"--http.address ${cfg.http.listenAddress}"
"--http.port ${toString cfg.http.port}"
] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\"");

in {
imports = [
(mkRenamedOptionModule [ "services" "snapserver" "controlPort"] [ "services" "snapserver" "tcp" "port" ])
Copy link
Contributor

Choose a reason for hiding this comment

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

Adjust line 282 to fix the deprecation warning.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed. Good catch.

];

###### interface

Expand All @@ -67,6 +82,15 @@ in {
'';
};

listenAddress = mkOption {
type = types.str;
default = "::";
example = "0.0.0.0";
description = ''
The address where snapclients can connect.
'';
};

port = mkOption {
type = types.port;
default = 1704;
Expand All @@ -75,24 +99,100 @@ in {
'';
};

controlPort = mkOption {
openFirewall = mkOption {
type = types.bool;
default = true;
description = ''
Whether to automatically open the specified ports in the firewall.
'';
};

inherit sampleFormat;
inherit codec;

streamBuffer = mkOption {
type = with types; nullOr int;
default = null;
description = ''
Stream read (input) buffer in ms.
'';
example = 20;
};

buffer = mkOption {
type = with types; nullOr int;
default = null;
description = ''
Network buffer in ms.
'';
example = 1000;
};

sendToMuted = mkOption {
type = types.bool;
default = false;
description = ''
Send audio to muted clients.
'';
};

tcp.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable the JSON-RPC via TCP.
'';
};

tcp.listenAddress = mkOption {
type = types.str;
default = "::";
example = "0.0.0.0";
description = ''
The address where the TCP JSON-RPC listens on.
'';
};

tcp.port = mkOption {
type = types.port;
default = 1705;
description = ''
The port for control connections (JSON-RPC).
The port where the TCP JSON-RPC listens on.
'';
};

openFirewall = mkOption {
http.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to automatically open the specified ports in the firewall.
Whether to enable the JSON-RPC via HTTP.
'';
};

inherit sampleFormat;
inherit codec;
http.listenAddress = mkOption {
type = types.str;
default = "::";
example = "0.0.0.0";
description = ''
The address where the HTTP JSON-RPC listens on.
'';
};

http.port = mkOption {
type = types.port;
default = 1780;
description = ''
The port where the HTTP JSON-RPC listens on.
'';
};

http.docRoot = mkOption {
type = with types; nullOr path;
default = null;
description = ''
Path to serve from the HTTP servers root.
'';
};

streams = mkOption {
type = with types; attrsOf (submodule {
Expand Down Expand Up @@ -147,34 +247,7 @@ in {
};
'';
};

streamBuffer = mkOption {
type = with types; nullOr int;
default = null;
description = ''
Stream read (input) buffer in ms.
'';
example = 20;
};

buffer = mkOption {
type = with types; nullOr int;
default = null;
description = ''
Network buffer in ms.
'';
example = 1000;
};

sendToMuted = mkOption {
type = types.bool;
default = false;
description = ''
Send audio to muted clients.
'';
};
};

};


Expand Down Expand Up @@ -206,7 +279,10 @@ in {
};
};

networking.firewall.allowedTCPPorts = optionals cfg.openFirewall [ cfg.port cfg.controlPort ];
networking.firewall.allowedTCPPorts =
optionals cfg.openFirewall [ cfg.port ]
++ optional cfg.tcp.enable cfg.tcp.port
++ optional cfg.http.enable cfg.http.port;
};

meta = {
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ in
simple = handleTest ./simple.nix {};
slurm = handleTest ./slurm.nix {};
smokeping = handleTest ./smokeping.nix {};
snapcast = handleTest ./snapcast.nix {};
snapper = handleTest ./snapper.nix {};
sogo = handleTest ./sogo.nix {};
solr = handleTest ./solr.nix {};
Expand Down
58 changes: 58 additions & 0 deletions nixos/tests/snapcast.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import ./make-test-python.nix ({ pkgs, ...} :

let
port = 10004;
tcpPort = 10005;
httpPort = 10080;
in {
name = "snapcast";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ hexa ];
};

nodes = {
server = {
services.snapserver = {
enable = true;
port = port;
tcp.port = tcpPort;
http.port = httpPort;
streams = {
mpd = {
type = "pipe";
location = "/run/snapserver/mpd";
};
bluetooth = {
type = "pipe";
location = "/run/snapserver/bluetooth";
};
};
};
};
};

testScript = ''
import json

get_rpc_version = {"id": "1", "jsonrpc": "2.0", "method": "Server.GetRPCVersion"}

start_all()

server.wait_for_unit("snapserver.service")
server.wait_until_succeeds("ss -ntl | grep -q ${toString port}")
server.wait_until_succeeds("ss -ntl | grep -q ${toString tcpPort}")
server.wait_until_succeeds("ss -ntl | grep -q ${toString httpPort}")

with subtest("check that pipes are created"):
server.succeed("test -p /run/snapserver/mpd")
server.succeed("test -p /run/snapserver/bluetooth")

with subtest("test tcp json-rpc"):
server.succeed(f"echo '{json.dumps(get_rpc_version)}' | nc -w 1 localhost ${toString tcpPort}")

with subtest("test http json-rpc"):
server.succeed(
"curl --fail http://localhost:${toString httpPort}/jsonrpc -d '{json.dumps(get_rpc_version)}'"
)
'';
})
5 changes: 4 additions & 1 deletion pkgs/applications/audio/snapcast/default.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{ stdenv, lib, fetchFromGitHub, cmake, pkgconfig
, alsaLib, asio, avahi, boost170, flac, libogg, libvorbis, soxr }:
, alsaLib, asio, avahi, boost170, flac, libogg, libvorbis, soxr
, nixosTests }:

let

Expand Down Expand Up @@ -57,6 +58,8 @@ stdenv.mkDerivation rec {
cp -r ../doc/* ../*.md $out/share/doc/snapcast
'';

passthru.tests.snapcast = nixosTests.snapcast;

meta = with lib; {
description = "Synchronous multi-room audio player";
homepage = "https://github.com/badaix/snapcast";
Expand Down