2020-12-22 11:37:31 +02:00
|
|
|
-- WirePlumber
|
|
|
|
|
--
|
|
|
|
|
-- Copyright © 2020 Collabora Ltd.
|
|
|
|
|
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
|
|
|
--
|
|
|
|
|
-- SPDX-License-Identifier: MIT
|
|
|
|
|
|
2021-02-22 12:39:06 -05:00
|
|
|
-- Receive script arguments from config.lua
|
|
|
|
|
local config = ...
|
|
|
|
|
|
|
|
|
|
-- ensure config.move and config.follow are not nil
|
|
|
|
|
config.move = config.move or false
|
|
|
|
|
config.follow = config.follow or false
|
|
|
|
|
|
2020-12-22 11:37:31 +02:00
|
|
|
target_class_assoc = {
|
|
|
|
|
["Stream/Input/Audio"] = "Audio/Source",
|
|
|
|
|
["Stream/Output/Audio"] = "Audio/Sink",
|
|
|
|
|
["Stream/Input/Video"] = "Video/Source",
|
|
|
|
|
["Stream/Output/Video"] = "Video/Sink",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reverse_direction = {
|
|
|
|
|
["input"] = "output",
|
|
|
|
|
["output"] = "input",
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-11 15:08:07 -05:00
|
|
|
default_endpoint_key = {
|
|
|
|
|
["input"] = "default.session.endpoint.sink",
|
|
|
|
|
["output"] = "default.session.endpoint.source",
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-22 12:39:06 -05:00
|
|
|
metadata_key_target_class_assoc = {
|
|
|
|
|
["default.session.endpoint.sink"] = {
|
|
|
|
|
["audio"] = "Stream/Output/Audio",
|
|
|
|
|
["video"] = "Stream/Output/Video",
|
|
|
|
|
},
|
|
|
|
|
["default.session.endpoint.source"] = {
|
|
|
|
|
["audio"] = "Stream/Input/Audio",
|
|
|
|
|
["video"] = "Stream/Input/Video",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default_endpoint_target = {
|
|
|
|
|
["Stream/Input/Audio"] = nil,
|
|
|
|
|
["Stream/Output/Audio"] = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-- Endpoint Ids not linked to its node.target prop
|
|
|
|
|
auto_linked_endpoints = {}
|
|
|
|
|
|
|
|
|
|
function createLink (ep, target)
|
2021-03-09 13:13:14 -05:00
|
|
|
local ep_id = ep['bound-id']
|
|
|
|
|
local target_id = target['bound-id']
|
|
|
|
|
local ep_is_output = (ep.direction == "output")
|
|
|
|
|
local props = {
|
|
|
|
|
['endpoint-link.output.endpoint'] = (ep_is_output and ep_id) or target_id,
|
|
|
|
|
['endpoint-link.output.stream'] = -1,
|
|
|
|
|
['endpoint-link.input.endpoint'] = (ep_is_output and target_id) or ep_id,
|
|
|
|
|
['endpoint-link.input.stream'] = -1,
|
|
|
|
|
}
|
|
|
|
|
ep:create_link (props)
|
2021-02-22 12:39:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function isEndpointLinkedWith (session, ep, target)
|
|
|
|
|
local ep_id = ep["bound_id"]
|
|
|
|
|
local target_id = target["bound_id"]
|
|
|
|
|
for link in session:iterate_links() do
|
2021-03-09 13:13:14 -05:00
|
|
|
local out_ep, in_ep = link:get_linked_object_ids()
|
2021-02-22 12:39:06 -05:00
|
|
|
if (out_ep == ep_id and in_ep == target_id) or
|
|
|
|
|
(out_ep == target_id and in_ep == ep_id) then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function moveEndpoint (session, ep, target)
|
|
|
|
|
local ep_id = ep['bound-id']
|
|
|
|
|
local ep_is_output = (ep.direction == "output")
|
|
|
|
|
local total_links = 0
|
|
|
|
|
local moving = false
|
|
|
|
|
|
|
|
|
|
-- return if already moved
|
|
|
|
|
if isEndpointLinkedWith(session, ep, target) then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- destroy all previous links
|
|
|
|
|
for link in session:iterate_links() do
|
2021-03-09 13:13:14 -05:00
|
|
|
local out_ep, in_ep = link:get_linked_object_ids()
|
2021-02-22 12:39:06 -05:00
|
|
|
if (ep_is_output and out_ep == ep_id) or
|
|
|
|
|
(not ep_is_output and in_ep == ep_id) then
|
|
|
|
|
local curr_target = nil
|
|
|
|
|
total_links = total_links + 1
|
|
|
|
|
-- create new link when all previous links were destroyed
|
|
|
|
|
link:connect ("pw-proxy-destroyed", function (l)
|
|
|
|
|
total_links = total_links - 1
|
|
|
|
|
if total_links == 0 then
|
|
|
|
|
createLink (ep, target)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
link:request_destroy ()
|
|
|
|
|
moving = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- create link if never linked
|
|
|
|
|
if not moving then
|
|
|
|
|
createLink (ep, target)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function moveEndpointFromNodeId (ep_node_id, target_node_id)
|
|
|
|
|
for session in om_session:iterate() do
|
2021-03-02 12:56:28 +02:00
|
|
|
local ep = session:lookup_endpoint {
|
2021-02-22 12:39:06 -05:00
|
|
|
Constraint { "node.id", "=", tostring(ep_node_id), type = "pw" }
|
2021-03-02 12:56:28 +02:00
|
|
|
}
|
2021-02-22 12:39:06 -05:00
|
|
|
if ep then
|
2021-03-02 12:56:28 +02:00
|
|
|
local target = session:lookup_endpoint {
|
2021-02-22 12:39:06 -05:00
|
|
|
Constraint { "node.id", "=", tostring(target_node_id), type = "pw" }
|
2021-03-02 12:56:28 +02:00
|
|
|
}
|
2021-02-22 12:39:06 -05:00
|
|
|
if target then
|
|
|
|
|
moveEndpoint (session, ep, target)
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function reevaluateAutoLinkedEndpoints (ep_media_class, target_id)
|
|
|
|
|
-- make sure the target Id has changed
|
|
|
|
|
if default_endpoint_target[ep_media_class] == target_id then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
default_endpoint_target[ep_media_class] = target_id
|
|
|
|
|
|
|
|
|
|
-- move auto linked endpoints to the new target
|
2021-03-02 14:08:43 +02:00
|
|
|
for session in om_session:iterate() do
|
2021-03-02 12:56:28 +02:00
|
|
|
local target = session:lookup_endpoint {
|
2021-02-22 12:39:06 -05:00
|
|
|
Constraint { "bound-id", "=", target_id, type = "gobject" }
|
2021-03-02 12:56:28 +02:00
|
|
|
}
|
2021-02-22 12:39:06 -05:00
|
|
|
if target then
|
2021-03-02 12:56:28 +02:00
|
|
|
for ep in session:iterate_endpoints {
|
2021-02-22 12:39:06 -05:00
|
|
|
Constraint { "media-class", "=", ep_media_class, type = "gobject" },
|
2021-03-02 12:56:28 +02:00
|
|
|
} do
|
2021-02-22 12:39:06 -05:00
|
|
|
if auto_linked_endpoints[ep["bound-id"]] == true then
|
|
|
|
|
moveEndpoint (session, ep, target)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-12-22 11:37:31 +02:00
|
|
|
function findTarget (session, ep)
|
|
|
|
|
local target = nil
|
2021-02-22 12:39:06 -05:00
|
|
|
local auto_linked = false
|
2020-12-22 11:37:31 +02:00
|
|
|
|
|
|
|
|
Log.trace(session, "Searching link target for " .. ep['bound-id'] ..
|
|
|
|
|
" (name:'" .. ep['name'] ..
|
|
|
|
|
"', media_class:'" .. ep['media-class'] .. "')");
|
|
|
|
|
|
|
|
|
|
-- honor node.target, if present
|
|
|
|
|
if ep.properties["node.target"] then
|
|
|
|
|
local id = ep.properties["node.target"]
|
|
|
|
|
for candidate_ep in session:iterate_endpoints() do
|
|
|
|
|
if candidate_ep.properties["node.id"] == id or
|
|
|
|
|
candidate_ep["bound-id"] == id
|
|
|
|
|
then
|
|
|
|
|
target = candidate_ep
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- try to find the best target
|
|
|
|
|
if not target then
|
2021-01-11 15:08:07 -05:00
|
|
|
local metadata = om_metadata:lookup()
|
2020-12-22 11:37:31 +02:00
|
|
|
local direction = reverse_direction[ep['direction']]
|
|
|
|
|
local media_class = target_class_assoc[ep['media-class']]
|
|
|
|
|
local highest_prio = -1
|
|
|
|
|
|
|
|
|
|
for candidate_ep in session:iterate_endpoints() do
|
|
|
|
|
if candidate_ep['direction'] == direction and
|
|
|
|
|
candidate_ep['media-class'] == media_class
|
|
|
|
|
then
|
2021-02-22 12:39:06 -05:00
|
|
|
-- we consider auto linked any target that is not in node.target prop
|
|
|
|
|
auto_linked = true
|
|
|
|
|
|
2021-01-11 15:08:07 -05:00
|
|
|
-- honor default endpoint, if present
|
|
|
|
|
if metadata then
|
|
|
|
|
local key = default_endpoint_key[direction]
|
|
|
|
|
local value = metadata:find(session['bound-id'], key)
|
|
|
|
|
if candidate_ep['bound-id'] == tonumber(value) then
|
|
|
|
|
target = candidate_ep
|
|
|
|
|
Log.debug(session, "choosing default endpoint " .. target['bound-id']);
|
|
|
|
|
break
|
|
|
|
|
end
|
2020-12-22 11:37:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local prio = tonumber(candidate_ep.properties["endpoint.priority"]) or 0
|
|
|
|
|
if highest_prio < prio then
|
|
|
|
|
highest_prio = prio
|
|
|
|
|
target = candidate_ep
|
|
|
|
|
Log.debug(session, "considering endpoint " .. target['bound-id'] ..
|
|
|
|
|
", priority " .. prio);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2021-02-22 12:39:06 -05:00
|
|
|
return target, auto_linked
|
2020-12-22 11:37:31 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function handleEndpoint (session, ep)
|
|
|
|
|
-- No need to link if autoconnect == false
|
|
|
|
|
local autoconnect = ep.properties['endpoint.autoconnect']
|
|
|
|
|
if autoconnect ~= 'true' and autoconnect ~= '1' then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local ep_id = ep['bound-id']
|
|
|
|
|
|
|
|
|
|
-- check if this endpoint is already linked
|
|
|
|
|
for link in session:iterate_links() do
|
2021-03-09 13:13:14 -05:00
|
|
|
local out_ep, in_ep = link:get_linked_object_ids()
|
2020-12-22 11:37:31 +02:00
|
|
|
if out_ep == ep_id or in_ep == ep_id then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- if not, find a suitable target and link
|
2021-02-22 12:39:06 -05:00
|
|
|
local target, auto_linked = findTarget (session, ep)
|
2020-12-22 11:37:31 +02:00
|
|
|
if target then
|
2021-02-22 12:39:06 -05:00
|
|
|
createLink (ep, target)
|
|
|
|
|
auto_linked_endpoints[ep_id] = auto_linked
|
2020-12-22 11:37:31 +02:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function handleLink (link)
|
|
|
|
|
-- activate all inactive links
|
|
|
|
|
if link:get_state() == "inactive" then
|
|
|
|
|
link:request_state("active")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2021-01-11 15:08:07 -05:00
|
|
|
om_metadata = ObjectManager { Interest { type = "metadata" } }
|
2021-02-22 12:39:06 -05:00
|
|
|
om_session = ObjectManager { Interest { type = "session" } }
|
2020-12-22 11:37:31 +02:00
|
|
|
|
2021-02-22 12:39:06 -05:00
|
|
|
om_session:connect("object-added", function (om, session)
|
2020-12-22 11:37:31 +02:00
|
|
|
session:connect('endpoints-changed', function (session)
|
|
|
|
|
for ep in session:iterate_endpoints() do
|
|
|
|
|
handleEndpoint(session, ep)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
session:connect('links-changed', function (session)
|
|
|
|
|
for link in session:iterate_links() do
|
|
|
|
|
handleLink (link)
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
end)
|
|
|
|
|
|
2021-02-22 12:39:06 -05:00
|
|
|
om_metadata:connect("object-added", function (om, metadata)
|
|
|
|
|
metadata:connect("changed", function (m, subject, key, t, value)
|
|
|
|
|
if config.move and key == "target.node" then
|
|
|
|
|
moveEndpointFromNodeId (subject, tonumber (value))
|
|
|
|
|
elseif config.follow and string.find(key, "default.session.endpoint") then
|
2021-03-02 12:56:28 +02:00
|
|
|
local session = om_session:lookup {
|
2021-02-22 12:39:06 -05:00
|
|
|
Constraint { "bound-id", "=", subject, type = "gobject" }
|
2021-03-02 12:56:28 +02:00
|
|
|
}
|
2021-02-22 12:39:06 -05:00
|
|
|
if session then
|
|
|
|
|
local target_class =
|
|
|
|
|
metadata_key_target_class_assoc[key][session.properties["session.name"]]
|
|
|
|
|
if target_class then
|
|
|
|
|
reevaluateAutoLinkedEndpoints (target_class, tonumber (value))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end)
|
|
|
|
|
end)
|
|
|
|
|
|
2021-01-11 15:08:07 -05:00
|
|
|
om_metadata:activate()
|
2021-02-22 12:39:06 -05:00
|
|
|
om_session:activate()
|