2021-03-23 15:08:03 -04:00
|
|
|
-- WirePlumber
|
|
|
|
|
--
|
|
|
|
|
-- Copyright © 2021 Collabora Ltd.
|
|
|
|
|
-- @author Julian Bouzas <julian.bouzas@collabora.com>
|
|
|
|
|
--
|
|
|
|
|
-- SPDX-License-Identifier: MIT
|
|
|
|
|
|
2022-06-20 18:15:04 +05:30
|
|
|
-- create-item.lua script takes pipewire nodes and creates session items(a.k.a
|
|
|
|
|
-- linkable) objects out of them.
|
|
|
|
|
|
2021-03-23 15:08:03 -04:00
|
|
|
items = {}
|
|
|
|
|
|
2021-10-08 00:09:42 +03:00
|
|
|
function configProperties(node)
|
|
|
|
|
local np = node.properties
|
|
|
|
|
local properties = {
|
|
|
|
|
["item.node"] = node,
|
|
|
|
|
["item.plugged.usec"] = GLib.get_monotonic_time(),
|
2022-05-19 10:12:38 +05:30
|
|
|
["item.features.no-dsp"] =
|
|
|
|
|
Settings.get_boolean ("default-policy-audio.no-dsp"),
|
2021-10-08 00:09:42 +03:00
|
|
|
["item.features.monitor"] = true,
|
|
|
|
|
["item.features.control-port"] = false,
|
|
|
|
|
["node.id"] = node["bound-id"],
|
|
|
|
|
["client.id"] = np["client.id"],
|
|
|
|
|
["object.path"] = np["object.path"],
|
2022-02-27 23:08:21 +02:00
|
|
|
["object.serial"] = np["object.serial"],
|
|
|
|
|
["target.object"] = np["target.object"],
|
2021-11-04 22:17:17 +05:30
|
|
|
["priority.session"] = np["priority.session"],
|
2021-11-26 14:43:04 +00:00
|
|
|
["device.id"] = np["device.id"],
|
|
|
|
|
["card.profile.device"] = np["card.profile.device"],
|
2021-10-08 00:09:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for k, v in pairs(np) do
|
|
|
|
|
if k:find("^node") or k:find("^stream") or k:find("^media") then
|
|
|
|
|
properties[k] = v
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local media_class = properties["media.class"] or ""
|
|
|
|
|
|
|
|
|
|
if not properties["media.type"] then
|
|
|
|
|
for _, i in ipairs({ "Audio", "Video", "Midi" }) do
|
|
|
|
|
if media_class:find(i) then
|
|
|
|
|
properties["media.type"] = i
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
properties["item.node.type"] =
|
|
|
|
|
media_class:find("^Stream/") and "stream" or "device"
|
|
|
|
|
|
|
|
|
|
if media_class:find("Sink") or
|
|
|
|
|
media_class:find("Input") or
|
|
|
|
|
media_class:find("Duplex") then
|
|
|
|
|
properties["item.node.direction"] = "input"
|
|
|
|
|
elseif media_class:find("Source") or media_class:find("Output") then
|
|
|
|
|
properties["item.node.direction"] = "output"
|
|
|
|
|
end
|
|
|
|
|
return properties
|
|
|
|
|
end
|
|
|
|
|
|
2022-05-20 17:43:43 +03:00
|
|
|
AsyncEventHook {
|
|
|
|
|
priority = 10,
|
|
|
|
|
type = "on-event",
|
2022-06-30 10:03:18 +05:30
|
|
|
name = "create-item-node-added",
|
2022-05-20 17:43:43 +03:00
|
|
|
interests = {
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-added" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Stream/*", type = "pw-global" },
|
|
|
|
|
},
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-added" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Video/*", type = "pw-global" },
|
|
|
|
|
},
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-added" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
|
|
|
|
Constraint { "wireplumber.is-endpoint", "-", type = "pw" },
|
|
|
|
|
},
|
2021-06-10 16:38:34 +03:00
|
|
|
},
|
2022-05-20 17:43:43 +03:00
|
|
|
steps = {
|
|
|
|
|
start = {
|
|
|
|
|
next = "register",
|
|
|
|
|
execute = function (event, transition)
|
|
|
|
|
local node = event:get_subject()
|
|
|
|
|
local id = node["bound-id"]
|
|
|
|
|
local item
|
|
|
|
|
local item_type
|
|
|
|
|
|
|
|
|
|
local media_class = node.properties['media.class']
|
|
|
|
|
if string.find (media_class, "Audio") then
|
|
|
|
|
item_type = "si-audio-adapter"
|
|
|
|
|
else
|
|
|
|
|
item_type = "si-node"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- create item
|
|
|
|
|
item = SessionItem (item_type)
|
|
|
|
|
items[id] = item
|
|
|
|
|
|
|
|
|
|
-- configure item
|
|
|
|
|
if not item:configure(configProperties(node)) then
|
|
|
|
|
transition:return_error("failed to configure item for node " .. tostring(id))
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- activate item
|
|
|
|
|
item:activate (Features.ALL, function (_, e)
|
|
|
|
|
if e then
|
|
|
|
|
transition:return_error("failed to activate item: " .. tostring(e));
|
|
|
|
|
else
|
|
|
|
|
transition:advance()
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
end,
|
|
|
|
|
},
|
|
|
|
|
register = {
|
|
|
|
|
next = "none",
|
|
|
|
|
execute = function (event, transition)
|
|
|
|
|
local node = event:get_subject()
|
|
|
|
|
local id = node["bound-id"]
|
|
|
|
|
local item = items[id]
|
|
|
|
|
|
|
|
|
|
Log.info(item, "activated item for node " .. tostring(id))
|
|
|
|
|
item:register ()
|
|
|
|
|
transition:advance()
|
2022-05-20 17:43:43 +03:00
|
|
|
|
|
|
|
|
props = {}
|
|
|
|
|
props["event.subject.type"] = "linkable"
|
|
|
|
|
EventDispatcher.push_event { type = "object-added",
|
|
|
|
|
priority = 50, properties = props, subject = item}
|
2022-05-20 17:43:43 +03:00
|
|
|
end,
|
|
|
|
|
},
|
2021-06-10 16:38:34 +03:00
|
|
|
},
|
2022-05-20 17:43:43 +03:00
|
|
|
}:register()
|
|
|
|
|
|
|
|
|
|
SimpleEventHook {
|
|
|
|
|
priority = 10,
|
|
|
|
|
type = "on-event",
|
2022-06-30 10:03:18 +05:30
|
|
|
name = "create-item-node-removed",
|
2022-05-20 17:43:43 +03:00
|
|
|
interests = {
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-removed" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Stream/*", type = "pw-global" },
|
|
|
|
|
},
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-removed" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Video/*", type = "pw-global" },
|
|
|
|
|
},
|
|
|
|
|
EventInterest {
|
|
|
|
|
Constraint { "event.type", "=", "object-removed" },
|
|
|
|
|
Constraint { "event.subject.type", "=", "node" },
|
|
|
|
|
Constraint { "media.class", "#", "Audio/*", type = "pw-global" },
|
|
|
|
|
Constraint { "wireplumber.is-endpoint", "-", type = "pw" },
|
|
|
|
|
},
|
2021-06-10 16:38:34 +03:00
|
|
|
},
|
2022-05-20 17:43:43 +03:00
|
|
|
execute = function (_, event)
|
|
|
|
|
local node = event:get_subject()
|
|
|
|
|
local id = node["bound-id"]
|
|
|
|
|
if items[id] then
|
|
|
|
|
items[id]:remove ()
|
|
|
|
|
items[id] = nil
|
|
|
|
|
end
|
2022-05-20 17:43:43 +03:00
|
|
|
|
|
|
|
|
props = {}
|
|
|
|
|
props["event.subject.type"] = "linkable"
|
|
|
|
|
EventDispatcher.push_event { type = "object-removed",
|
|
|
|
|
priority = 50, properties = props, subject = item}
|
2021-03-23 15:08:03 -04:00
|
|
|
end
|
2022-05-20 17:43:43 +03:00
|
|
|
}:register()
|