fmt(host/cerithium-telescopium): audio-server

This commit is contained in:
Malte Tammena 2024-11-01 19:52:41 +01:00
parent 51afc6542d
commit 00e2f4d87e
2 changed files with 92 additions and 78 deletions

View file

@ -8,91 +8,100 @@
}: let }: let
snapcastPipewireFifo = "/run/snapserver/pipewire"; snapcastPipewireFifo = "/run/snapserver/pipewire";
in { in {
# === Mopidy === # === Mopidy ===
# services.mopidy = { # services.mopidy = {
# enable = true; # enable = true;
# extensionPackages = [ # extensionPackages = [
# pkgs.mopidy-mpd # pkgs.mopidy-mpd
# pkgs.mopidy-iris # pkgs.mopidy-iris
# ]; # ];
# configuration = '' # configuration = ''
# [http] # [http]
# enabled = true # enabled = true
# hostname = 0.0.0.0 # hostname = 0.0.0.0
# port = 6680 # port = 6680
# [audio] # [audio]
# mixer = software # mixer = software
# mixer_volume = 100 # mixer_volume = 100
# output = audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/run/snapserver/mopidy # output = audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/run/snapserver/mopidy
# [file] # [file]
# enabled = false # enabled = false
# ''; # '';
# }; # };
# networking.firewall.allowedTCPPorts = [6680]; # networking.firewall.allowedTCPPorts = [6680];
# === Snapcast Server === # === Snapcast Server ===
services.snapserver = { services.snapserver = {
enable = true; enable = true;
openFirewall = true; openFirewall = true;
http.docRoot = "${pkgs.snapweb}/"; http.docRoot = "${pkgs.snapweb}/";
streams = { streams = {
pipewire = { pipewire = {
type = "pipe"; type = "pipe";
codec = "flac"; codec = "flac";
location = snapcastPipewireFifo; location = snapcastPipewireFifo;
};
}; };
}; };
systemd.tmpfiles.settings."99-snapserver"."/run/snapserver".d = {}; };
systemd.tmpfiles.settings."99-snapserver"."/run/snapserver".d = {};
# === Pipewire === # === Pipewire ===
# Create a sink that writes everything to the snapcast fifo # Create a sink that writes everything to the snapcast fifo
services.pipewire.extraConfig.pipewire."20-snapcast-sink"."context.modules" = lib.singleton { services.pipewire.extraConfig.pipewire."20-snapcast-sink"."context.modules" = lib.singleton {
name = "libpipewire-module-pipe-tunnel"; name = "libpipewire-module-pipe-tunnel";
args = { args = {
"tunnel.mode" = "sink"; "tunnel.mode" = "sink";
"pipe.filename" = snapcastPipewireFifo; "pipe.filename" = snapcastPipewireFifo;
"audio.format" = "S16LE"; "audio.format" = "S16LE";
"audio.rate" = "48000"; "audio.rate" = "48000";
"audio.channels" = "2"; "audio.channels" = "2";
"audio.position" = [ "FL" "FR" ]; "audio.position" = ["FL" "FR"];
"stream.props" = { "stream.props" = {
"node.name" = "Snapcast"; "node.name" = "Snapcast";
};
}; };
}; };
# Instruct pipewire to connect bluetooth input streams to the Snapcast sink };
services.pipewire.extraConfig.pipewire."21-bluetooth-to-snapcast"."node.rules" = lib.singleton { # Instruct pipewire to connect bluetooth input streams to the Snapcast sink
matches = lib.singleton { "node.name" = "~bluez_input.*"; }; services.pipewire.extraConfig.pipewire."21-bluetooth-to-snapcast"."node.rules" = lib.singleton {
actions.update-props."target.object" = "Snapcast"; matches = lib.singleton {"node.name" = "~bluez_input.*";};
}; actions.update-props."target.object" = "Snapcast";
# TODO: };
services.pipewire.extraConfig.pipewire-pulse."50-networking"."pulse.cmd" = [ # TODO:
{ cmd = "load-module"; args = "module-native-protocol-tcp listen=0.0.0.0"; } services.pipewire.extraConfig.pipewire-pulse."50-networking"."pulse.cmd" = [
{ cmd = "load-module"; args = "module-zeroconf-discover"; } {
{ cmd = "load-module"; args = "module-zeroconf-publish"; } cmd = "load-module";
args = "module-native-protocol-tcp listen=0.0.0.0";
}
{
cmd = "load-module";
args = "module-zeroconf-discover";
}
{
cmd = "load-module";
args = "module-zeroconf-publish";
}
];
# === Bluetooth input ===
hardware.bluetooth.settings = {
# Configure the bluetooth adapter to be an audio sink
General.Enable = "Source";
General.DiscoverableTimeout = 0;
General.AlwaysPairable = true;
General.JustWorksRepairing = "always";
};
environment.etc."bluetooth/pin-file".text = ''
* 124356
'';
systemd.user.services.bluetooth-agent = {
wantedBy = [
"default.target"
]; ];
serviceConfig = {
# === Bluetooth input === ExecStart = "${pkgs.bluez-tools}/bin/bt-agent --pin /etc/bluetooth/pin-file --capability NoInputNoOutput";
hardware.bluetooth.settings = { Slice = "session.slice";
# Configure the bluetooth adapter to be an audio sink
General.Enable = "Source";
General.DiscoverableTimeout = 0;
General.AlwaysPairable = true;
General.JustWorksRepairing = "always";
};
environment.etc."bluetooth/pin-file".text = ''
* 124356
'';
systemd.user.services.bluetooth-agent = {
wantedBy = [
"default.target"
];
serviceConfig = {
ExecStart = "${pkgs.bluez-tools}/bin/bt-agent --pin /etc/bluetooth/pin-file --capability NoInputNoOutput";
Slice="session.slice";
};
}; };
};
} }

View file

@ -7,6 +7,11 @@
let cfg = config.services.snapclient; in let cfg = config.services.snapclient; in
{ {
options.services.snapclient.enable = lib.mkEnableOption "a local snapclient service"; options.services.snapclient.enable = lib.mkEnableOption "a local snapclient service";
options.services.snapclient.latency = lib.mkOption {
type = lib.types.number;
description = "latency of the PCM device";
default = 0;
};
config.systemd.user.services.snapclient = lib.mkIf cfg.enable { config.systemd.user.services.snapclient = lib.mkIf cfg.enable {
wantedBy = lib.warnIfNot config.services.pipewire.enable "Pipewire is not running, snapclient won't work" [ wantedBy = lib.warnIfNot config.services.pipewire.enable "Pipewire is not running, snapclient won't work" [
@ -17,7 +22,7 @@ let cfg = config.services.snapclient; in
"pipewire.service" "pipewire.service"
]; ];
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.snapcast}/bin/snapclient --host snapserver --player pulse"; ExecStart = "${pkgs.snapcast}/bin/snapclient --host snapserver --player pulse --latency ${builtins.toString cfg.latency}";
Slice="session.slice"; Slice="session.slice";
}; };
}; };