From 5f6fbdc0ac10863a510097a54d52fdc2a57d7312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Tue, 9 Jun 2026 14:39:32 +0200 Subject: [PATCH] feat: audio cast --- hosts/MONSTER/default.nix | 12 +- hosts/MONSTER/home.nix | 1 + hosts/aero/home.nix | 8 +- hosts/shark/default.nix | 12 +- hosts/shark/home.nix | 8 +- modules/home-manager/packages/default.nix | 1 - modules/nixos/default.nix | 1 + modules/nixos/hardware/audio-share.nix | 157 ++++++++++++++++++++++ modules/nixos/hardware/audio-share.sh | 22 +++ modules/nixos/hardware/fv43u.nix | 2 +- modules/nixos/hardware/q3279vwf.nix | 31 +++-- modules/nixos/shell/waybar.nix | 2 +- 12 files changed, 241 insertions(+), 16 deletions(-) create mode 100644 modules/nixos/hardware/audio-share.nix create mode 100644 modules/nixos/hardware/audio-share.sh diff --git a/hosts/MONSTER/default.nix b/hosts/MONSTER/default.nix index aab2060..bdcb85e 100644 --- a/hosts/MONSTER/default.nix +++ b/hosts/MONSTER/default.nix @@ -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; diff --git a/hosts/MONSTER/home.nix b/hosts/MONSTER/home.nix index 132ef42..da293c7 100644 --- a/hosts/MONSTER/home.nix +++ b/hosts/MONSTER/home.nix @@ -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; diff --git a/hosts/aero/home.nix b/hosts/aero/home.nix index a9bcc4f..e3a1f49 100755 --- a/hosts/aero/home.nix +++ b/hosts/aero/home.nix @@ -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 = [ { diff --git a/hosts/shark/default.nix b/hosts/shark/default.nix index 5979b78..4854f42 100644 --- a/hosts/shark/default.nix +++ b/hosts/shark/default.nix @@ -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; diff --git a/hosts/shark/home.nix b/hosts/shark/home.nix index 4fc142a..6f69392 100755 --- a/hosts/shark/home.nix +++ b/hosts/shark/home.nix @@ -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 = { diff --git a/modules/home-manager/packages/default.nix b/modules/home-manager/packages/default.nix index 6d45117..a299efe 100644 --- a/modules/home-manager/packages/default.nix +++ b/modules/home-manager/packages/default.nix @@ -14,7 +14,6 @@ tone-mapping = "mobius"; }; }; - services.jellyfin-mpv-shim.enable = true; home.packages = with pkgs; [ # nix cachix diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index 0089a52..9260eb5 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -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 diff --git a/modules/nixos/hardware/audio-share.nix b/modules/nixos/hardware/audio-share.nix new file mode 100644 index 0000000..de4e989 --- /dev/null +++ b/modules/nixos/hardware/audio-share.nix @@ -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; + } + ]; + }; + } + ]; + }; + }; + }; + }; +} diff --git a/modules/nixos/hardware/audio-share.sh b/modules/nixos/hardware/audio-share.sh new file mode 100644 index 0000000..d43c2e1 --- /dev/null +++ b/modules/nixos/hardware/audio-share.sh @@ -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 diff --git a/modules/nixos/hardware/fv43u.nix b/modules/nixos/hardware/fv43u.nix index 003831f..5f09748 100644 --- a/modules/nixos/hardware/fv43u.nix +++ b/modules/nixos/hardware/fv43u.nix @@ -66,7 +66,7 @@ in sdr_min_luminance = 0.25; sdr_max_luminance = 250; icc = toString ./fv43u.icc; - cm = "dcip3"; + # cm = "dcip3"; }; }; diff --git a/modules/nixos/hardware/q3279vwf.nix b/modules/nixos/hardware/q3279vwf.nix index a2f9a91..6609607 100644 --- a/modules/nixos/hardware/q3279vwf.nix +++ b/modules/nixos/hardware/q3279vwf.nix @@ -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 }; }; } diff --git a/modules/nixos/shell/waybar.nix b/modules/nixos/shell/waybar.nix index c0bf7c5..7f46a8d 100644 --- a/modules/nixos/shell/waybar.nix +++ b/modules/nixos/shell/waybar.nix @@ -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" =