Skip to content
Snippets Groups Projects
auto-connect-ports.lua 5.54 KiB
Newer Older
  • Learn to ignore specific revisions
  • -- As explained on: https://bennett.dev/auto-link-pipewire-ports-wireplumber/
    --
    -- This script automatically connects the audio device specified to liquidsoap.
    -- Thanks to Bennett Hardwick <me@bennetthardwick.com> 
    
    -- Link two ports together
    function link_port(output_port, input_port)
      if not input_port or not output_port then
        return false
      end
    
      local link_args = {
        ["link.input.node"] = input_port.properties["node.id"],
        ["link.input.port"] = input_port.properties["object.id"],
    
        ["link.output.node"] = output_port.properties["node.id"],
        ["link.output.port"] = output_port.properties["object.id"],
        
        -- The node never got created if it didn't have this field set to something
        ["object.id"] = nil,
    
        -- I was running into issues when I didn't have this set
        ["object.linger"] = true,
    
        ["node.description"] = "AURA Link created by auto_connect_ports"
      }
    
      local link = Link("link-factory", link_args)
      link:activate(1)
    
      return true
    end
    
    function delete_link(link_om, output_port, input_port)
      print("Trying to delete")
    
      if not input_port or not output_port then
        print("No ports")
        return false
      end
    
      local link = link_om:lookup {
        Constraint {
          "link.input.node", "equals", input_port.properties["node.id"]
        },
        Constraint {
          "link.input.port", "equals", input_port.properties["object.id"],
        },
        Constraint {
          "link.output.node", "equals", output_port.properties["node.id"],
        },
        Constraint {
          "link.output.port", "equals", output_port.properties["object.id"],
        }
      }
    
      if not link then
    
        print("No link!")
    
        return
      end
    
      print("Deleting link!")
    
      link:request_destroy()
    end
    
    -- Automatically link ports together by their specific audio channels.
    --
    -- ┌──────────────────┐         ┌───────────────────┐
    -- │                  │         │                   │
    -- │               FL ├────────►│ AUX0              │
    -- │      OUTPUT      │         │                   │
    -- │               FR ├────────►│ AUX1  INPUT       │
    -- │                  │         │                   │
    -- └──────────────────┘         │ AUX2              │
    --                              │                   │
    --                              └───────────────────┘
    -- 
    -- -- Call this method inside a script in global scope
    --
    -- auto_connect_ports {
    --
    --   -- A constraint for all the required ports of the output device 
    --   output = Constraint { "node.name"}
    --
    --   -- A constraint for all the required ports of the input device 
    --   input = Constraint { .. }
    --
    --   -- A mapping of output audio channels to input audio channels
    --
    --   connections = {
    --     ["FL"] = "AUX0"
    --     ["FR"] = "AUX1"
    --   }
    --
    -- }
    --
    function auto_connect_ports(args)
      local output_om = ObjectManager {
        Interest {
          type = "port",
          args["output"],
          Constraint { "port.direction", "equals", "out" }
        }
      }
    
      local input_om = ObjectManager {
        Interest {
          type = "port",
          args["input"],
          Constraint { "port.direction", "equals", "in" }
        }
      }
    
      local all_links = ObjectManager {
        Interest {
          type = "link",
        }
      }
    
      local unless = nil
    
      if args["unless"] then
        unless = ObjectManager {
          Interest {
            type = "port",
            args["unless"],
            Constraint { "port.direction", "equals", "in" }
          }
        }
    
      end
    
      -- handle the connect argument
      function _connect()
        local delete_links = unless and unless:get_n_objects() > 0
    
        for output_name, input_name in pairs(args.connect) do
          local output = output_om:lookup { Constraint { "port.name", "matches", string.format("*%s", output_name) }}
          local input =  input_om:lookup { Constraint { "port.name", "matches", string.format("*%s", input_name) }}
    
          if delete_links then
            delete_link(all_links, output, input)
          else
            link_port(output, input)
          end
        end
      end
    
      output_om:connect("object-added", _connect)
      input_om:connect("object-added", _connect)
      all_links:connect("object-added", _connect)
    
      output_om:activate()
      input_om:activate()
      all_links:activate()
    
      if unless then
        unless:connect("object-added", _connect)
        unless:connect("object-removed", _connect)
        unless:activate()
      end
    end
    
    -- 
    -- Fill in your port.alias and port.name
    --
    
    -- Auto connect Yamaha sink to the first two channels of the Yamaha
    
    local audio_source_input = os.getenv("AURA_ENGINE_INPUT_DEVICE")
    local audio_input_channel_left = os.getenv("AURA_ENGINE_INPUT_CHANNEL_LEFT")
    local audio_input_channel_right = os.getenv("AURA_ENGINE_INPUT_CHANNEL_RIGHT")
    local audio_source_output = os.getenv("AURA_ENGINE_OUTPUT_DEVICE")
    local audio_output_channel_left = os.getenv("AURA_ENGINE_OUTPUT_CHANNEL_LEFT")
    local audio_output_channel_right = os.getenv("AURA_ENGINE_OUTPUT_CHANNEL_RIGHT")
    
    -- print(string.format("%s_*", audio_source_input))
    
    auto_connect_ports {
    
      output = Constraint { "port.alias", "matches", audio_source_input .. "_*" },
    
      input = Constraint { "port.alias", "matches", "in_line_0:*" },
    
        [audio_input_channel_left] = "in_0",
        [audio_input_channel_right] = "in_1"
    
      }
    }
    auto_connect_ports {
    
      output = Constraint { "port.alias", "matches", "lineout_0:*" },
    
      input = Constraint { "port.alias", "matches", audio_source_output .. "_*" },
    
        ["out_0"] = audio_output_channel_left,
        ["out_1"] = audio_output_channel_right