mirror of
https://github.com/Theaninova/TheaninovOS.git
synced 2026-07-25 10:04:44 +00:00
158 lines
4.7 KiB
Nix
158 lines
4.7 KiB
Nix
{
|
|
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;
|
|
}
|
|
];
|
|
};
|
|
}
|
|
];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|