feat: audio cast

This commit is contained in:
2026-06-09 14:39:32 +02:00
parent cf2108ad82
commit 5f6fbdc0ac
12 changed files with 241 additions and 16 deletions
+11 -1
View File
@@ -67,7 +67,17 @@
hardware = {
amdgpu.preset.default.enable = true;
audio.preset.pipewire.enable = true;
audio = {
preset.pipewire.enable = true;
audio-share = {
enable = true;
partner = {
ip = "192.168.0.51";
name = "Luci";
combine = "astro-a50-eq-harman-in";
};
};
};
cc1.enable = true;
fv43u.enable = true;
astro-a50.enable = true;
+1
View File
@@ -14,6 +14,7 @@
extraConfig.PROJECTS = "${config.home.homeDirectory}/Projects";
};
programs.zoxide.enable = true;
services.jellyfin-mpv-shim.enable = true;
wayland.windowManager.hyprland.settings.device =
let
targetDPI = 1200;
+7 -1
View File
@@ -13,6 +13,12 @@
packages = with pkgs; [
blueman
kdePackages.okular
(pkgs.writeShellApplication {
name = "shut";
text = ''
shutdown now
'';
})
];
};
wayland.windowManager.hyprland.settings = {
@@ -23,7 +29,7 @@
mfact = 0.65;
always_keep_position = true;
};
input.kb_options = [ "lv3:caps_switch" ];
input.kb_options = "lv3:caps_switch";
};
monitor = [
{
+11 -1
View File
@@ -72,7 +72,17 @@
hardware = {
q3279vwf.enable = true;
audio.preset.pipewire.enable = true;
audio = {
preset.pipewire.enable = true;
audio-share = {
enable = true;
partner = {
ip = "192.168.0.84";
name = "Thea";
combine = "alsa_output.usb-SteelSeries_Arctis_Pro_Wireless-00.pro-output-0";
};
};
};
cc1.enable = true;
nvidia.preset.proprietary.enable = true;
+7 -1
View File
@@ -15,9 +15,15 @@
kdePackages.okular
bitbox
gamma-launcher
(pkgs.writeShellApplication {
name = "shut";
text = ''
shutdown now
'';
})
];
};
wayland.windowManager.hyprland.settings.config.input.kb_options = [ "lv3:caps_switch" ];
wayland.windowManager.hyprland.settings.config.input.kb_options = "lv3:caps_switch";
services.nextcloud-client.enable = true;
systemd.user.services = {
nm-applet = {
@@ -14,7 +14,6 @@
tone-mapping = "mobius";
};
};
services.jellyfin-mpv-shim.enable = true;
home.packages = with pkgs; [
# nix
cachix
+1
View File
@@ -11,6 +11,7 @@
./fonts/nerd-fonts.nix
./fonts/open-dyslexic.nix
./hardware/audio-share.nix
./hardware/astro-a50.nix
./hardware/audio.nix
./hardware/gbmonctl.nix
+157
View File
@@ -0,0 +1,157 @@
{
pkgs,
lib,
config,
username,
...
}:
with lib;
let
cfg = config.hardware.audio.audio-share;
in
{
options.hardware.audio.audio-share = {
enable = mkEnableOption "LAN Audio Sharing";
partner = mkOption {
type = types.submodule {
options = {
ip = mkOption {
type = types.str;
description = "The IP address of the partner machine to share audio with.";
};
name = mkOption {
type = types.str;
description = "Name of the partner machine (for display purposes)";
};
combine = mkOption {
type = types.str;
description = "Name of the sink to combine the shared output with";
};
};
};
};
};
config =
let
sourcePort = 10001;
repairPort = 10002;
controlPort = 10003;
sinkName = "combined_output_3";
in
mkIf cfg.enable {
networking.firewall.allowedUDPPorts = [
sourcePort
repairPort
controlPort
];
home-manager.users.${username} = {
programs.waybar.settings.mainBar = {
"pulseaudio" = {
format-icons.${sinkName} = "󱝉";
on-click-right = lib.getExe (
pkgs.writeShellApplication {
name = "toggle-audio-share";
runtimeEnv = {
SINK_A = sinkName;
SINK_B = cfg.partner.combine;
};
text = builtins.readFile ./audio-share.sh;
}
);
};
};
xdg.configFile = {
"pipewire/pipewire.conf.d/52-audio-share.conf".text = builtins.toJSON {
"context.modules" = [
{
name = "libpipewire-module-roc-source";
args = {
"local.ip" = "0.0.0.0";
"roc.resampler.backend" = "default";
"roc.resampler.profile" = "default";
"roc.latency-tuner.backend" = "default";
"roc.latency-tuner.profile" = "default";
"fec.code" = "default";
"sess.latency.msec" = 100;
"local.source.port" = sourcePort;
"local.repair.port" = repairPort;
"local.control.port" = controlPort;
};
}
];
};
"pipewire/pipewire.conf.d/52-audio-share-sink.conf".text = builtins.toJSON {
"context.modules" = [
{
name = "libpipewire-module-roc-sink";
args = {
"fec.code" = "default";
"remote.ip" = cfg.partner.ip;
"remote.source.port" = sourcePort;
"remote.repair.port" = repairPort;
"remote.control.port" = controlPort;
"sink.props" = {
"node.name" = cfg.partner.name;
"node.description" = cfg.partner.name;
};
};
}
{
name = "libpipewire-module-combine-stream";
args = {
"combine.mode" = "sink";
"node.name" = sinkName;
"node.description" = "Shared Audio Output";
"combine.latency-compensate" = true;
"combine.props" = {
audio.position = [
"FL"
"FR"
];
};
"stream.rules" =
let
actions = {
create-stream = {
"combine.audio.position" = [
"FL"
"FR"
];
"audio.position" = [
"FL"
"FR"
];
};
};
in
[
{
matches = [
{
"media.class" = "Audio/Sink";
"node.name" = cfg.partner.combine;
}
];
inherit actions;
}
{
matches = [
{
"media.class" = "Audio/Sink";
"node.name" = cfg.partner.name;
}
];
inherit actions;
}
];
};
}
];
};
};
};
};
}
+22
View File
@@ -0,0 +1,22 @@
set -eu
get_id() {
pw-dump | jq -r --arg name "$1" '
.[]
| select(.type == "PipeWire:Interface:Node")
| select(.info.props["node.name"] == $name)
| .id
'
}
ID_A=$(get_id "$SINK_A")
ID_B=$(get_id "$SINK_B")
CURRENT_ID=$(wpctl inspect @DEFAULT_AUDIO_SINK@ |
awk '$1 == "id" { gsub(",", "", $2); print $2 }')
if [ "$CURRENT_ID" = "$ID_A" ]; then
wpctl set-default "$ID_B"
else
wpctl set-default "$ID_A"
fi
+1 -1
View File
@@ -66,7 +66,7 @@ in
sdr_min_luminance = 0.25;
sdr_max_luminance = 250;
icc = toString ./fv43u.icc;
cm = "dcip3";
# cm = "dcip3";
};
};
+22 -9
View File
@@ -18,18 +18,31 @@ in
fonts.fontconfig.subpixel.rgba = "bgr";
home-manager.users.${username}.wayland.windowManager.hyprland.settings = {
general.layout = "master";
master = {
orientation = "right";
mfact = 0.65;
always_keep_position = true;
config = {
general.layout = "master";
master = {
orientation = "right";
mfact = 0.65;
always_keep_position = true;
};
xwayland.force_zero_scaling = true;
misc.vrr = 0; # VA suffers from VRR flicker
};
monitor = [
"HDMI-A-1,2560x1440@75,0x0,1"
"DP-1,1920x1080@144,auto-center-right,1,transform,3"
{
output = "HDMI-A-1";
mode = "2560x1440@75";
position = "0x0";
scale = 1;
}
{
output = "DP-1";
mode = "1920x1080@144";
position = "auto-center-right";
scale = 1;
transform = 3;
}
];
xwayland.force_zero_scaling = true;
misc.vrr = 0; # VA suffers from VRR flicker
};
};
}
+1 -1
View File
@@ -76,7 +76,7 @@ in
"pulseaudio" = {
format = "{icon} {volume}%";
format-icons = {
"alsa_output.usb-Turtle_Beach_Turtle_Beach_Stealth_700_G2_MAX-01.iec958-stereo" = "󰋋";
"astro-a50-eq-harman-in" = "󰋋";
"alsa_output.pci-0000_0a_00.4.analog-stereo" = "󰓃";
"alsa_output.pci-0000_08_00.1.hdmi-stereo-extra4" = "󰽟";
"alsa_output.usb-Blue_Microphones_Yeti_Stereo_Microphone_797_2018_11_12_79383-00.analog-stereo" =