2021-01-20 09:53:57 +02:00
|
|
|
-- WirePlumber
|
|
|
|
|
--
|
|
|
|
|
-- Copyright © 2021 Collabora Ltd.
|
|
|
|
|
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
|
|
|
--
|
|
|
|
|
-- SPDX-License-Identifier: MIT
|
|
|
|
|
|
2023-09-29 23:13:28 +03:00
|
|
|
cutils = require ("common-utils")
|
2023-05-19 20:12:08 +03:00
|
|
|
log = Log.open_topic ("s-monitors")
|
2022-09-06 07:31:21 +05:30
|
|
|
|
2023-09-29 23:13:28 +03:00
|
|
|
config = {}
|
2023-11-13 13:46:58 +02:00
|
|
|
config.reserve_device = Core.test_feature ("monitor.alsa.reserve-device")
|
2024-03-04 16:27:37 +02:00
|
|
|
config.properties = Conf.get_section_as_properties ("monitor.alsa.properties")
|
2024-03-04 17:03:57 +02:00
|
|
|
config.rules = Conf.get_section_as_json ("monitor.alsa.rules", Json.Array {})
|
2021-02-15 18:49:57 +02:00
|
|
|
|
2022-05-18 10:51:41 -04:00
|
|
|
-- unique device/node name tables
|
|
|
|
|
device_names_table = nil
|
|
|
|
|
node_names_table = nil
|
|
|
|
|
|
2021-02-18 10:23:07 +02:00
|
|
|
function nonempty(str)
|
|
|
|
|
return str ~= "" and str or nil
|
|
|
|
|
end
|
|
|
|
|
|
2022-10-06 11:37:50 -04:00
|
|
|
function applyDefaultDeviceProperties (properties)
|
|
|
|
|
properties["api.alsa.use-acp"] = true
|
|
|
|
|
properties["api.acp.auto-port"] = false
|
2023-12-09 15:52:24 +02:00
|
|
|
properties["api.dbus.ReserveDevice1.Priority"] = -20
|
2022-10-06 11:37:50 -04:00
|
|
|
end
|
|
|
|
|
|
2022-07-07 20:58:36 +03:00
|
|
|
function createNode(parent, id, obj_type, factory, properties)
|
2021-01-20 09:53:57 +02:00
|
|
|
local dev_props = parent.properties
|
2021-02-15 18:49:57 +02:00
|
|
|
|
|
|
|
|
-- set the device id and spa factory name; REQUIRED, do not change
|
|
|
|
|
properties["device.id"] = parent["bound-id"]
|
|
|
|
|
properties["factory.name"] = factory
|
|
|
|
|
|
|
|
|
|
-- set the default pause-on-idle setting
|
|
|
|
|
properties["node.pause-on-idle"] = false
|
|
|
|
|
|
|
|
|
|
-- try to negotiate the max ammount of channels
|
|
|
|
|
if dev_props["api.alsa.use-acp"] ~= "true" then
|
|
|
|
|
properties["audio.channels"] = properties["audio.channels"] or "64"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local dev = properties["api.alsa.pcm.device"]
|
|
|
|
|
or properties["alsa.device"] or "0"
|
|
|
|
|
local subdev = properties["api.alsa.pcm.subdevice"]
|
|
|
|
|
or properties["alsa.subdevice"] or "0"
|
2021-01-20 09:53:57 +02:00
|
|
|
local stream = properties["api.alsa.pcm.stream"] or "unknown"
|
2021-02-15 18:49:57 +02:00
|
|
|
local profile = properties["device.profile.name"]
|
|
|
|
|
or (stream .. "." .. dev .. "." .. subdev)
|
2021-01-20 09:53:57 +02:00
|
|
|
local profile_desc = properties["device.profile.description"]
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
-- set priority
|
|
|
|
|
if not properties["priority.driver"] then
|
|
|
|
|
local priority = (dev == "0") and 1000 or 744
|
|
|
|
|
if stream == "capture" then
|
|
|
|
|
priority = priority + 1000
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
priority = priority - (tonumber(dev) * 16) - tonumber(subdev)
|
|
|
|
|
|
2023-02-14 17:43:25 +01:00
|
|
|
if profile:find("^pro%-") then
|
|
|
|
|
priority = priority + 500
|
|
|
|
|
elseif profile:find("^analog%-") then
|
2021-02-15 18:49:57 +02:00
|
|
|
priority = priority + 9
|
|
|
|
|
elseif profile:find("^iec958%-") then
|
|
|
|
|
priority = priority + 8
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
properties["priority.driver"] = priority
|
|
|
|
|
properties["priority.session"] = priority
|
|
|
|
|
end
|
|
|
|
|
|
2021-01-20 09:53:57 +02:00
|
|
|
-- ensure the node has a media class
|
|
|
|
|
if not properties["media.class"] then
|
|
|
|
|
if stream == "capture" then
|
|
|
|
|
properties["media.class"] = "Audio/Source"
|
|
|
|
|
else
|
|
|
|
|
properties["media.class"] = "Audio/Sink"
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ensure the node has a name
|
2021-02-15 18:49:57 +02:00
|
|
|
if not properties["node.name"] then
|
|
|
|
|
local name =
|
|
|
|
|
(stream == "capture" and "alsa_input" or "alsa_output")
|
|
|
|
|
.. "." ..
|
|
|
|
|
(dev_props["device.name"]:gsub("^alsa_card%.(.+)", "%1") or
|
|
|
|
|
dev_props["device.name"] or
|
|
|
|
|
"unnamed-device")
|
|
|
|
|
.. "." ..
|
|
|
|
|
profile
|
|
|
|
|
|
2021-02-15 19:18:07 +02:00
|
|
|
-- sanitize name
|
|
|
|
|
name = name:gsub("([^%w_%-%.])", "_")
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
properties["node.name"] = name
|
|
|
|
|
|
2024-05-31 17:03:11 +03:00
|
|
|
log:info ("Creating node " .. name)
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
-- deduplicate nodes with the same name
|
|
|
|
|
for counter = 2, 99, 1 do
|
2022-05-18 10:51:41 -04:00
|
|
|
if node_names_table[properties["node.name"]] ~= true then
|
|
|
|
|
node_names_table[properties["node.name"]] = true
|
2021-02-15 18:49:57 +02:00
|
|
|
break
|
|
|
|
|
end
|
2022-05-18 10:51:41 -04:00
|
|
|
properties["node.name"] = name .. "." .. counter
|
2024-05-31 17:03:11 +03:00
|
|
|
log:info ("deduplicating node name -> " .. properties["node.name"])
|
2021-02-15 18:49:57 +02:00
|
|
|
end
|
2024-11-23 16:35:50 +02:00
|
|
|
else
|
|
|
|
|
log:info ("Creating node " .. properties["node.name"])
|
2021-02-15 18:49:57 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- and a nick
|
2022-03-01 12:11:25 +02:00
|
|
|
local nick = nonempty(properties["node.nick"])
|
|
|
|
|
or nonempty(properties["api.alsa.pcm.name"])
|
|
|
|
|
or nonempty(properties["alsa.name"])
|
|
|
|
|
or nonempty(profile_desc)
|
2021-01-20 09:53:57 +02:00
|
|
|
or dev_props["device.nick"]
|
2022-03-08 11:56:34 +01:00
|
|
|
if nick == "USB Audio" then
|
|
|
|
|
nick = dev_props["device.nick"]
|
|
|
|
|
end
|
2021-02-18 09:02:41 +02:00
|
|
|
-- also sanitize nick, replace ':' with ' '
|
|
|
|
|
properties["node.nick"] = nick:gsub("(:)", " ")
|
2021-01-20 09:53:57 +02:00
|
|
|
|
|
|
|
|
-- ensure the node has a description
|
|
|
|
|
if not properties["node.description"] then
|
2021-02-18 10:23:07 +02:00
|
|
|
local desc = nonempty(dev_props["device.description"]) or "unknown"
|
|
|
|
|
local name = nonempty(properties["api.alsa.pcm.name"]) or
|
|
|
|
|
nonempty(properties["api.alsa.pcm.id"]) or dev
|
2021-01-20 09:53:57 +02:00
|
|
|
|
|
|
|
|
if profile_desc then
|
2021-02-18 09:02:41 +02:00
|
|
|
desc = desc .. " " .. profile_desc
|
2021-02-18 10:23:07 +02:00
|
|
|
elseif subdev ~= "0" then
|
2021-02-18 09:02:41 +02:00
|
|
|
desc = desc .. " (" .. name .. " " .. subdev .. ")"
|
2021-02-18 10:23:07 +02:00
|
|
|
elseif dev ~= "0" then
|
2021-02-18 09:02:41 +02:00
|
|
|
desc = desc .. " (" .. name .. ")"
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
2021-02-18 09:02:41 +02:00
|
|
|
|
|
|
|
|
-- also sanitize description, replace ':' with ' '
|
|
|
|
|
properties["node.description"] = desc:gsub("(:)", " ")
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
|
|
|
|
|
2021-03-26 17:29:25 +02:00
|
|
|
-- add api.alsa.card.* properties for rule matching purposes
|
|
|
|
|
for k, v in pairs(dev_props) do
|
|
|
|
|
if k:find("^api%.alsa%.card%..*") then
|
|
|
|
|
properties[k] = v
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2024-03-18 17:03:44 +02:00
|
|
|
-- add cpu.vm.name for rule matching purposes
|
monitors/alsa: remove vm.node.defaults and use match rules instead
The vm.node.defaults logic which was inherited from p-m-s is not really
good because it seems like different VM hardware requires different
values for the defaults. Also, passthrough USB hardware should not
inerhit these values, they just cause trouble.
Instead, we can use rules to match the vm.type and specific device
properties to set a more informed period & headroom.
For now, I am also decreasing the default headroom down to 2048, which
works for me and perhaps it's a good default. We can always add more
rules here and fine-tune per vm type and virtual hardware.
See !394, #316, #348, #507, #162, pipewire#3452
2023-11-14 21:32:18 +02:00
|
|
|
local vm_type = Core.get_vm_type()
|
|
|
|
|
if nonempty(vm_type) then
|
2024-03-18 17:03:44 +02:00
|
|
|
properties["cpu.vm.name"] = vm_type
|
2022-06-28 14:31:17 +03:00
|
|
|
end
|
|
|
|
|
|
2022-05-02 12:49:50 +05:30
|
|
|
-- apply properties from rules defined in JSON .conf file
|
2024-03-04 17:03:57 +02:00
|
|
|
properties = JsonUtils.match_rules_update_properties (config.rules, properties)
|
|
|
|
|
|
2024-03-08 12:45:26 +05:30
|
|
|
if cutils.parseBool (properties ["node.disabled"]) then
|
|
|
|
|
log:notice ("ALSA node " .. properties["node.name"] .. " disabled")
|
2022-11-08 04:20:21 +05:30
|
|
|
node_names_table [properties ["node.name"]] = nil
|
2022-01-12 12:13:08 +01:00
|
|
|
return
|
|
|
|
|
end
|
2021-01-20 09:53:57 +02:00
|
|
|
|
|
|
|
|
-- create the node
|
|
|
|
|
local node = Node("adapter", properties)
|
2024-11-23 16:35:50 +02:00
|
|
|
node:activate(Feature.Proxy.BOUND, function (_, err)
|
|
|
|
|
if err then
|
|
|
|
|
log:warning ("Failed to create " .. properties ["node.name"]
|
|
|
|
|
.. ": " .. tostring(err))
|
|
|
|
|
|
|
|
|
|
-- if it fails, object-removed gets called with missing
|
|
|
|
|
-- properties, so clean up already here
|
|
|
|
|
node_names_table [properties ["node.name"]] = nil
|
|
|
|
|
end
|
|
|
|
|
end)
|
2021-01-20 09:53:57 +02:00
|
|
|
parent:store_managed_object(id, node)
|
|
|
|
|
end
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
function createDevice(parent, id, factory, properties)
|
|
|
|
|
local device = SpaDevice(factory, properties)
|
2022-01-11 11:27:33 -05:00
|
|
|
if device then
|
|
|
|
|
device:connect("create-object", createNode)
|
2022-05-18 10:51:41 -04:00
|
|
|
device:connect("object-removed", function (parent, id)
|
|
|
|
|
local node = parent:get_managed_object(id)
|
2022-11-08 04:20:21 +05:30
|
|
|
if not node then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
2024-05-31 17:03:11 +03:00
|
|
|
local node_name = node.properties["node.name"]
|
2024-11-23 16:35:50 +02:00
|
|
|
if node_name ~= nil then
|
|
|
|
|
log:info ("Removing node " .. node_name)
|
|
|
|
|
node_names_table[node_name] = nil
|
|
|
|
|
else
|
|
|
|
|
log:info ("Removing node with missing node.name")
|
|
|
|
|
end
|
2022-05-18 10:51:41 -04:00
|
|
|
end)
|
2022-01-11 11:27:33 -05:00
|
|
|
device:activate(Feature.SpaDevice.ENABLED | Feature.Proxy.BOUND)
|
|
|
|
|
parent:store_managed_object(id, device)
|
|
|
|
|
else
|
2023-05-19 20:12:08 +03:00
|
|
|
log:warning ("Failed to create '" .. factory .. "' device")
|
2022-01-11 11:27:33 -05:00
|
|
|
end
|
2021-02-15 18:49:57 +02:00
|
|
|
end
|
|
|
|
|
|
2022-07-07 20:58:36 +03:00
|
|
|
function prepareDevice(parent, id, obj_type, factory, properties)
|
2021-02-15 18:49:57 +02:00
|
|
|
-- ensure the device has an appropriate name
|
|
|
|
|
local name = "alsa_card." ..
|
|
|
|
|
(properties["device.name"] or
|
|
|
|
|
properties["device.bus-id"] or
|
|
|
|
|
properties["device.bus-path"] or
|
2021-06-03 18:58:07 +03:00
|
|
|
tostring(id)):gsub("([^%w_%-%.])", "_")
|
2021-02-15 18:49:57 +02:00
|
|
|
|
|
|
|
|
properties["device.name"] = name
|
|
|
|
|
|
|
|
|
|
-- deduplicate devices with the same name
|
|
|
|
|
for counter = 2, 99, 1 do
|
2022-05-18 10:51:41 -04:00
|
|
|
if device_names_table[properties["device.name"]] ~= true then
|
|
|
|
|
device_names_table[properties["device.name"]] = true
|
2021-02-15 18:49:57 +02:00
|
|
|
break
|
|
|
|
|
end
|
2022-05-18 10:51:41 -04:00
|
|
|
properties["device.name"] = name .. "." .. counter
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ensure the device has a description
|
|
|
|
|
if not properties["device.description"] then
|
|
|
|
|
local d = nil
|
|
|
|
|
local f = properties["device.form-factor"]
|
|
|
|
|
local c = properties["device.class"]
|
2022-12-13 15:19:06 +01:00
|
|
|
local n = properties["api.alsa.card.name"]
|
2021-01-20 09:53:57 +02:00
|
|
|
|
2022-12-13 15:19:06 +01:00
|
|
|
if n == "Loopback" then
|
|
|
|
|
d = I18n.gettext("Loopback")
|
|
|
|
|
elseif f == "internal" then
|
2022-04-09 14:27:42 +03:00
|
|
|
d = I18n.gettext("Built-in Audio")
|
2021-01-20 09:53:57 +02:00
|
|
|
elseif c == "modem" then
|
2022-04-09 14:27:42 +03:00
|
|
|
d = I18n.gettext("Modem")
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
d = d or properties["device.product.name"]
|
|
|
|
|
or properties["api.alsa.card.name"]
|
|
|
|
|
or properties["alsa.card_name"]
|
|
|
|
|
or "Unknown device"
|
2021-01-20 09:53:57 +02:00
|
|
|
properties["device.description"] = d
|
|
|
|
|
end
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
-- ensure the device has a nick
|
|
|
|
|
properties["device.nick"] =
|
|
|
|
|
properties["device.nick"] or
|
2022-03-01 11:35:55 +02:00
|
|
|
properties["api.alsa.card.name"] or
|
|
|
|
|
properties["alsa.card_name"]
|
2021-02-15 18:49:57 +02:00
|
|
|
|
2021-01-20 09:53:57 +02:00
|
|
|
-- set the icon name
|
|
|
|
|
if not properties["device.icon-name"] then
|
|
|
|
|
local icon = nil
|
2021-02-15 18:49:57 +02:00
|
|
|
local icon_map = {
|
|
|
|
|
-- form factor -> icon
|
|
|
|
|
["microphone"] = "audio-input-microphone",
|
|
|
|
|
["webcam"] = "camera-web",
|
|
|
|
|
["handset"] = "phone",
|
|
|
|
|
["portable"] = "multimedia-player",
|
|
|
|
|
["tv"] = "video-display",
|
|
|
|
|
["headset"] = "audio-headset",
|
|
|
|
|
["headphone"] = "audio-headphones",
|
|
|
|
|
["speaker"] = "audio-speakers",
|
|
|
|
|
["hands-free"] = "audio-handsfree",
|
|
|
|
|
}
|
2021-01-20 09:53:57 +02:00
|
|
|
local f = properties["device.form-factor"]
|
|
|
|
|
local c = properties["device.class"]
|
|
|
|
|
local b = properties["device.bus"]
|
|
|
|
|
|
2021-02-15 18:49:57 +02:00
|
|
|
icon = icon_map[f] or ((c == "modem") and "modem") or "audio-card"
|
|
|
|
|
properties["device.icon-name"] = icon .. "-analog" .. (b and ("-" .. b) or "")
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
|
|
|
|
|
2022-05-02 12:49:50 +05:30
|
|
|
-- apply properties from rules defined in JSON .conf file
|
2023-11-07 12:44:13 +02:00
|
|
|
applyDefaultDeviceProperties (properties)
|
2024-03-04 17:03:57 +02:00
|
|
|
properties = JsonUtils.match_rules_update_properties (config.rules, properties)
|
2023-11-07 12:44:13 +02:00
|
|
|
|
2024-03-08 12:45:26 +05:30
|
|
|
if cutils.parseBool (properties ["device.disabled"]) then
|
|
|
|
|
log:notice ("ALSA card/device " .. properties ["device.name"] .. " disabled")
|
2022-11-08 04:20:21 +05:30
|
|
|
device_names_table [properties ["device.name"]] = nil
|
2022-01-12 12:13:08 +01:00
|
|
|
return
|
|
|
|
|
end
|
2021-02-15 18:49:57 +02:00
|
|
|
|
2021-01-20 09:53:57 +02:00
|
|
|
-- override the device factory to use ACP
|
2024-03-08 12:45:26 +05:30
|
|
|
if cutils.parseBool (properties ["api.alsa.use-acp"]) then
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info("Enabling the use of ACP on " .. properties["device.name"])
|
2021-01-20 09:53:57 +02:00
|
|
|
factory = "api.alsa.acp.device"
|
|
|
|
|
end
|
|
|
|
|
|
2021-01-26 17:24:52 +02:00
|
|
|
-- use device reservation, if available
|
2021-02-15 18:49:57 +02:00
|
|
|
if rd_plugin and properties["api.alsa.card"] then
|
2021-01-26 17:24:52 +02:00
|
|
|
local rd_name = "Audio" .. properties["api.alsa.card"]
|
|
|
|
|
local rd = rd_plugin:call("create-reservation",
|
2021-02-15 18:49:57 +02:00
|
|
|
rd_name,
|
2023-12-09 15:52:24 +02:00
|
|
|
cutils.get_application_name (),
|
2021-02-15 18:49:57 +02:00
|
|
|
properties["device.name"],
|
2023-12-09 15:52:24 +02:00
|
|
|
properties["api.dbus.ReserveDevice1.Priority"]);
|
2021-01-26 17:24:52 +02:00
|
|
|
|
|
|
|
|
properties["api.dbus.ReserveDevice1"] = rd_name
|
|
|
|
|
|
|
|
|
|
-- unlike pipewire-media-session, this logic here keeps the device
|
|
|
|
|
-- acquired at all times and destroys it if someone else acquires
|
|
|
|
|
rd:connect("notify::state", function (rd, pspec)
|
|
|
|
|
local state = rd["state"]
|
|
|
|
|
|
|
|
|
|
if state == "acquired" then
|
|
|
|
|
-- create the device
|
2021-02-15 18:49:57 +02:00
|
|
|
createDevice(parent, id, factory, properties)
|
2021-01-26 17:24:52 +02:00
|
|
|
|
|
|
|
|
elseif state == "available" then
|
|
|
|
|
-- attempt to acquire again
|
|
|
|
|
rd:call("acquire")
|
|
|
|
|
|
|
|
|
|
elseif state == "busy" then
|
|
|
|
|
-- destroy the device
|
|
|
|
|
parent:store_managed_object(id, nil)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
2021-11-23 13:17:29 +01:00
|
|
|
rd:connect("release-requested", function (rd)
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info("release requested")
|
2021-11-23 13:17:29 +01:00
|
|
|
parent:store_managed_object(id, nil)
|
|
|
|
|
rd:call("release")
|
|
|
|
|
end)
|
|
|
|
|
|
2021-01-26 17:24:52 +02:00
|
|
|
rd:call("acquire")
|
|
|
|
|
else
|
|
|
|
|
-- create the device
|
2021-02-15 18:49:57 +02:00
|
|
|
createDevice(parent, id, factory, properties)
|
2021-01-26 17:24:52 +02:00
|
|
|
end
|
2021-01-20 09:53:57 +02:00
|
|
|
end
|
|
|
|
|
|
2021-09-23 14:58:46 -04:00
|
|
|
function createMonitor ()
|
2022-09-08 12:37:13 -04:00
|
|
|
local m = SpaDevice("api.alsa.enum.udev", config.properties)
|
2021-09-23 14:58:46 -04:00
|
|
|
if m == nil then
|
2024-02-10 11:20:07 +02:00
|
|
|
log:notice("PipeWire's ALSA SPA plugin is missing or broken. " ..
|
|
|
|
|
"Sound cards will not be supported")
|
2021-09-23 14:58:46 -04:00
|
|
|
return nil
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- handle create-object to prepare device
|
|
|
|
|
m:connect("create-object", prepareDevice)
|
|
|
|
|
|
2022-05-18 10:51:41 -04:00
|
|
|
-- 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)
|
2022-11-08 04:20:21 +05:30
|
|
|
if not device then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
2022-05-18 10:51:41 -04:00
|
|
|
if rd_plugin then
|
2021-09-23 14:58:46 -04:00
|
|
|
local rd_name = device.properties["api.dbus.ReserveDevice1"]
|
|
|
|
|
if rd_name then
|
|
|
|
|
rd_plugin:call("destroy-reservation", rd_name)
|
|
|
|
|
end
|
2022-05-18 10:51:41 -04:00
|
|
|
end
|
|
|
|
|
device_names_table[device.properties["device.name"]] = nil
|
2022-06-16 15:45:29 -04:00
|
|
|
for managed_node in device:iterate_managed_objects() do
|
|
|
|
|
node_names_table[managed_node.properties["node.name"]] = nil
|
|
|
|
|
end
|
2022-05-18 10:51:41 -04:00
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
-- reset the name tables to make sure names are recycled
|
|
|
|
|
device_names_table = {}
|
|
|
|
|
node_names_table = {}
|
2021-09-16 16:31:59 +05:30
|
|
|
|
2021-09-23 14:58:46 -04:00
|
|
|
-- activate monitor
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info("Activating ALSA monitor")
|
2021-09-23 14:58:46 -04:00
|
|
|
m:activate(Feature.SpaDevice.ENABLED)
|
|
|
|
|
return m
|
|
|
|
|
end
|
2021-01-26 17:24:52 +02:00
|
|
|
|
2021-02-03 13:00:40 +02:00
|
|
|
-- if the reserve-device plugin is enabled, at the point of script execution
|
|
|
|
|
-- it is expected to be connected. if it is not, assume the d-bus connection
|
|
|
|
|
-- has failed and continue without it
|
2023-11-13 13:46:58 +02:00
|
|
|
if config.reserve_device then
|
|
|
|
|
rd_plugin = Plugin.find("reserve-device")
|
|
|
|
|
end
|
2022-07-12 15:33:23 +02:00
|
|
|
if rd_plugin and rd_plugin:call("get-dbus")["state"] ~= "connected" then
|
2023-05-19 20:12:08 +03:00
|
|
|
log:notice("reserve-device plugin is not connected to D-Bus, "
|
2021-02-15 18:49:57 +02:00
|
|
|
.. "disabling device reservation")
|
2021-02-03 13:00:40 +02:00
|
|
|
rd_plugin = nil
|
|
|
|
|
end
|
2021-01-26 17:24:52 +02:00
|
|
|
|
2021-09-23 14:58:46 -04:00
|
|
|
-- handle rd_plugin state changes to destroy and re-create the ALSA monitor in
|
|
|
|
|
-- case D-Bus service is restarted
|
2021-02-03 13:00:40 +02:00
|
|
|
if rd_plugin then
|
2022-05-06 09:57:37 -04:00
|
|
|
local dbus = rd_plugin:call("get-dbus")
|
|
|
|
|
dbus:connect("notify::state", function (b, pspec)
|
|
|
|
|
local state = b["state"]
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info ("rd-plugin state changed to " .. state)
|
2021-09-23 14:58:46 -04:00
|
|
|
if state == "connected" then
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info ("Creating ALSA monitor")
|
2021-09-23 14:58:46 -04:00
|
|
|
monitor = createMonitor()
|
|
|
|
|
elseif state == "closed" then
|
2023-05-19 20:12:08 +03:00
|
|
|
log:info ("Destroying ALSA monitor")
|
2021-09-23 14:58:46 -04:00
|
|
|
monitor = nil
|
2021-02-03 13:00:40 +02:00
|
|
|
end
|
|
|
|
|
end)
|
2021-01-26 17:24:52 +02:00
|
|
|
end
|
2021-02-03 13:00:40 +02:00
|
|
|
|
2021-09-23 14:58:46 -04:00
|
|
|
-- create the monitor
|
|
|
|
|
monitor = createMonitor()
|