{ lib }:

rec {
  ## Renames an alsa device from a given `name` using the new `description`.
  ##
  #@ { name: String, description: String } -> { matches: List, apply_properties: Attrs }
  mkAlsaRename = { name, description }: {
    matches = [
      [
        [ "device.name" "matches" name ]
      ]
    ];
    # actions = { "update-props" = { "node.description" = description; }; };
    apply_properties = {
      "device.description" = description;
    };
  };

  ## Create a pipewire audio node.
  ##
  #@ { name: String, factory: String ? "adapter", ... } -> { factory: String, args: Attrs }
  mkAudioNode = args@{ name, factory ? "adapter", ... }: {
    inherit factory;
    args = (builtins.removeAttrs args [ "name" "description" ]) // {
      "node.name" = name;
      "node.description" = args.description or args."node.description";
      "factory.name" = args."factory.name" or "support.null-audio-sink";
    };
  };

  ## Create a virtual pipewire audio node.
  ##
  #@ { name: String, ... } -> { factory: "adapter", args: Attrs }
  mkVirtualAudioNode = args@{ name, ... }:
    mkAudioNode (args // {
      name = "virtual-${lib.toLower name}-audio";
      description = "${name} (Virtual)";
      "media.class" = args.class or args."media.class" or "Audio/Duplex";
      "object.linger" = args."object.linger" or true;
      "audio.position" = args."audio.position" or [ "FL" "FR" ];
      "monitor.channel-volumes" = args."monitor.channel-volumes" or true;
    });

  ## Connect two pipewire audio nodes
  ##
  #@ { name: String?, from: String, to: String, ... } -> { name: "libpipewire-module-loopback", args: Attrs }
  mkBridgeAudioModule = args@{ from, to, ... }: {
    name = "libpipewire-module-loopback";
    args = (builtins.removeAttrs args [ "from" "to" "name" ]) // {
      "node.name" =
        if args ? name then
          "${args.name}-bridge"
        else
          "${lib.toLower from}-to-${lib.toLower to}-bridge";
      "audio.position" = args."audio.position" or [ "FL" "FR" ];
      "capture.props" = {
        "node.target" = from;
      } // (args."capture.props" or { });
      "playback.props" = {
        "node.target" = to;
        "monitor.channel-volumes" = true;
      } // (args."playback.props" or { });
    };
  };
}
