https://gitlab.freedesktop.org/pipewire/wireplumber/-/commit/c00c5a6675b6640db13111c808eaa3251917c412

From c00c5a6675b6640db13111c808eaa3251917c412 Mon Sep 17 00:00:00 2001
From: Julian Bouzas <julian.bouzas@collabora.com>
Date: Wed, 18 May 2022 10:51:41 -0400
Subject: [PATCH] alsa.lua: fix device name deduplication when reservation is
 enabled

Fixes #241
---
 src/scripts/monitors/alsa.lua | 47 +++++++++++++++++++----------------
 1 file changed, 25 insertions(+), 22 deletions(-)

diff --git a/src/scripts/monitors/alsa.lua b/src/scripts/monitors/alsa.lua
index 01d241db..7beed3a8 100644
--- a/src/scripts/monitors/alsa.lua
+++ b/src/scripts/monitors/alsa.lua
@@ -11,6 +11,10 @@ local config = ... or {}
 -- ensure config.properties is not nil
 config.properties = config.properties or {}
 
+-- unique device/node name tables
+device_names_table = nil
+node_names_table = nil
+
 -- preprocess rules and create Interest objects
 for _, r in ipairs(config.rules or {}) do
   r.interests = {}
@@ -41,16 +45,6 @@ function rulesApplyProperties(properties)
   end
 end
 
-function findDuplicate(parent, id, property, value)
-  for i = 0, id - 1, 1 do
-    local obj = parent:get_managed_object(i)
-    if obj and obj.properties[property] == value then
-      return true
-    end
-  end
-  return false
-end
-
 function nonempty(str)
   return str ~= "" and str or nil
 end
@@ -125,11 +119,11 @@ function createNode(parent, id, type, factory, properties)
 
     -- deduplicate nodes with the same name
     for counter = 2, 99, 1 do
-      if findDuplicate(parent, id, "node.name", properties["node.name"]) then
-        properties["node.name"] = name .. "." .. counter
-      else
+      if node_names_table[properties["node.name"]] ~= true then
+        node_names_table[properties["node.name"]] = true
         break
       end
+      properties["node.name"] = name .. "." .. counter
     end
   end
 
@@ -186,6 +180,10 @@ function createDevice(parent, id, factory, properties)
   local device = SpaDevice(factory, properties)
   if device then
     device:connect("create-object", createNode)
+    device:connect("object-removed", function (parent, id)
+      local node = parent:get_managed_object(id)
+      node_names_table[node.properties["node.name"]] = nil
+    end)
     device:activate(Feature.SpaDevice.ENABLED | Feature.Proxy.BOUND)
     parent:store_managed_object(id, device)
   else
@@ -205,11 +203,11 @@ function prepareDevice(parent, id, type, factory, properties)
 
   -- deduplicate devices with the same name
   for counter = 2, 99, 1 do
-    if findDuplicate(parent, id, "device.name", properties["device.name"]) then
-      properties["device.name"] = name .. "." .. counter
-    else
+    if device_names_table[properties["device.name"]] ~= true then
+      device_names_table[properties["device.name"]] = true
       break
     end
+    properties["device.name"] = name .. "." .. counter
   end
 
   -- ensure the device has a description
@@ -337,16 +335,21 @@ function createMonitor ()
   -- handle create-object to prepare device
   m:connect("create-object", prepareDevice)
 
-  -- if dbus reservation, handle object-removed to destroy device reservations
-  if rd_plugin then
-    m:connect("object-removed", function (parent, id)
-      local device = parent:get_managed_object(id)
+  -- handle object-removed to destroy device reservations and recycle device name
+  m:connect("object-removed", function (parent, id)
+    local device = parent:get_managed_object(id)
+    if rd_plugin then
       local rd_name = device.properties["api.dbus.ReserveDevice1"]
       if rd_name then
         rd_plugin:call("destroy-reservation", rd_name)
       end
-    end)
-  end
+    end
+    device_names_table[device.properties["device.name"]] = nil
+  end)
+
+  -- reset the name tables to make sure names are recycled
+  device_names_table = {}
+  node_names_table = {}
 
   -- activate monitor
   Log.info("Activating ALSA monitor")
-- 
GitLab

