auto :ˆl–Ãa¾”ÔD¨ µÕÆ™¸ÛªbÑ¿Á „ ξÏa–Ü4ý()¨‰P@Š7fà€¦-ÿÀ?÷-- WirePlumber -- -- Copyright © 2021 Collabora Ltd. -- @author George Kiagiadakis -- -- SPDX-License-Identifier: MIT SPLIT_PCM_PARENT_OFFSET = 256 SPLIT_PCM_OFFSET = 512 cutils = require ("common-utils") log = Log.open_topic ("s-monitors") config = {} config.reserve_device = Core.test_feature ("monitor.alsa.reserve-device") config.properties = Conf.get_section_as_properties ("monitor.alsa.properties") config.rules = Conf.get_section_as_json ("monitor.alsa.rules", Json.Array {}) -- unique device/node name tables device_names_table = nil node_names_table = nil -- SPA ids to node names: name = id_name_table[device_id][node_id] id_name_table = nil function nonempty(str) return str ~= "" and str or nil end function applyDefaultDeviceProperties (properties) properties["api.alsa.use-acp"] = true properties["api.acp.auto-profile"] = false properties["api.acp.auto-port"] = false properties["api.dbus.ReserveDevice1.Priority"] = -20 properties["api.alsa.split-enable"] = true end function createSplitPCMHWNode(dev_props, properties) local skip_keys = { "api.alsa.split.position", "card.profile.device", "device.profile.description", "device.profile.name" } local props = {} for k, v in pairs(properties) do props[k] = v end for _, k in pairs(skip_keys) do props[k] = nil end -- create the underlying hidden ALSA node props["node.name"] = props["api.alsa.split.name"] props["node.description"] = string.format("%s %s", dev_props["device.description"], props["api.alsa.path"]:gsub("^[^,]*[,:]", "")) if props["api.alsa.pcm.stream"] == "capture" then props["media.class"] = "Audio/Source/Internal" else props["media.class"] = "Audio/Sink/Internal" end props["api.alsa.use-chmap"] = false props["api.alsa.split.parent"] = true props["audio.position"] = props["api.alsa.split.hw-position"] local channels = Json.Raw (props["api.alsa.split.hw-position"]):parse () props["audio.channels"] = tostring(#channels) props = JsonUtils.match_rules_update_properties (config.rules, props) if cutils.parseBool (props ["node.disabled"]) then log:notice ("ALSA node " .. props ["node.name"] .. " disabled") return nil end return Node("adapter", props) end function createSplitPCMLoopback(parent, id, obj_type, factory, properties) local skip_keys = { -- not suitable for loopback "audio.rate", "clock.quantum-limit", "factory.name", "node.driver", "node.pause-on-idle", "node.want-driver", "port.group", "priority.driver", "resample.disable", "resample.prefill", } local args local props = {} props["node.virtual"] = false for k, v in pairs(properties) do props[k] = v end for _, k in pairs(skip_keys) do props[k] = nil end local split_props = { ["node.name"] = properties["node.name"] .. ".split", ["node.description"] = string.format(I18n.gettext("Split %s"), properties["node.description"]), ["audio.position"] = properties["api.alsa.split.position"], ["stream.dont-remix"] = true, ["node.passive"] = true, ["node.dont-fallback"] = true, ["node.linger"] = true, ["state.restore-props"] = false, ["target.object"] = properties["api.alsa.split.name"], } if properties["api.alsa.pcm.stream"] == "playback" then props["media.class"] = "Audio/Sink" split_props["media.class"] = "Stream/Output/Audio/Internal" args = Json.Object { ["capture.props"] = Json.Object (props), ["playback.props"] = Json.Object (split_props), } else props["media.class"] = "Audio/Source" split_props["media.class"] = "Stream/Input/Audio/Internal" args = Json.Object { ["playback.props"] = Json.Object (props), ["capture.props"] = Json.Object (split_props), } end return LocalModule("libpipewire-module-loopback", args:get_data(), {}) end devices_om = ObjectManager { Interest { type = "device", } } split_nodes_om =