如何在 Fedora 35 中使用 WirePlumber 禁用音频接收器在空闲时挂起,以便在开始播放时音频不会延迟?

如何在 Fedora 35 中使用 WirePlumber 禁用音频接收器在空闲时挂起,以便在开始播放时音频不会延迟?

在 Fedora 35 中,WirePlumber 取代了 pipeline-media-session 作为音频会话管理器。 Linux 上的许多内置声卡上的音频存在一个非常烦人的问题,即在 3 秒内没有播放任何内容后,音频接收器会暂停。 3 秒后恢复播放时,音频会延迟或弹出。我们如何修复此默认行为?

答案1

相关的配置文件是/usr/share/wireplumber/main.lua.d/50-alsa-config.lua,但不要编辑它的系统版本!

您需要将其复制到/etc/wireplumber/main.lua.d/(全局配置)或~/.config/wireplumber/main.lua.d/(用户配置)并进行必要的更改。

最简单的方法是将其复制到全局配置位置,以便它适用于所有用户帐户:

sudo cp -a /usr/share/wireplumber/main.lua.d/50-alsa-config.lua /etc/wireplumber/main.lua.d/50-alsa-config.lua
sudo nano /etc/wireplumber/main.lua.d/50-alsa-config.lua

然后,您需要向下滚动到文件底部的该apply_properties部分,并在其中添加一行:

["session.suspend-timeout-seconds"] = 0

我做了更多的改变并为我自己的个人硬件定制了它。这是我的配置供参考,但此配置仅对我的确切设备有用。实际上,您只需要上面的行即可禁用自动挂起。将其添加到您自己的默认配置中。不要复制我的配置。我所做的其他更改是无关的。

alsa_monitor.properties = {
  ["alsa.jack-device"] = true,
  ["alsa.reserve"] = true,
  ["alsa.midi.monitoring"] = true
}

alsa_monitor.rules = {
{
    matches = {
      {
        { "device.name", "matches", "alsa_card.*" }
      }
    },
    apply_properties = {
      ["api.alsa.use-acp"] = true,
      ["api.acp.auto-profile"] = false,
      ["api.acp.auto-port"] = false
    }
  },
  {
    matches = {
      {
        { "node.name", "matches", "alsa_output.pci-0000_0c_00.4.iec958-ac3-surround-51" }
      }
    },
    apply_properties = {
      ["api.alsa.period-size"] = 128,
      ["api.alsa.headroom"] = 2048,
      ["session.suspend-timeout-seconds"] = 0
    }
  },
  { 
    matches = {
      {
        { "node.name", "matches", "alsa_input.usb-BEHRINGER_UMC202HD_192k-00.analog-mono" }
      }
    },
    apply_properties = {
      ["api.alsa.period-size"] = 128
    }
  }
}

设置该session.suspend-timeout-seconds属性以0防止挂起/睡眠行为。它完全禁用了该行为,如 WirePlumber 的源代码中所示。

必须重新启动 WirePlumber 才能使更改生效:

systemctl --user restart wireplumber

答案2

session.suspend-timeout-seconds在运行没有 WirePlumber 的 PipeWire 且使用 pipeline-media-session 的系统中,通常可以通过将 的底部部分更改为 0 来修复此问题/etc/pipewire/media-session.d/alsa-monitor.conf。但是,在 Fedora 35 安装中找不到此目录或任何会话监视器配置文件。实际上没有文档显示如何防止接收器在 3 秒内挂起,所以我必须自己解决这个问题。相反,我们必须修改 WirePlumber 脚本目录中的 Lua 脚本。导航至/usr/share/wireplumber/scripts/并为其创建备份副本suspend-node.lua。然后使用 sudo 权限在文本编辑器或终端中打开suspend-node.lua,并注释掉负责接收器超时和挂起接收器的代码块,使文件如下所示:

-- WirePlumber
--
-- Copyright © 2021 Collabora Ltd.
--    @author George Kiagiadakis <[email protected]>
--
-- SPDX-License-Identifier: MIT

om = ObjectManager {
  Interest { type = "node",
    Constraint { "media.class", "matches", "Audio/*" }
  },
  Interest { type = "node",
    Constraint { "media.class", "matches", "Video/*" }
  },
}

sources = {}

om:connect("object-added", function (om, node)
  node:connect("state-changed", function (node, old_state, cur_state)
    -- Always clear the current source if any
    local id = node["bound-id"]
    if sources[id] then
      sources[id]:destroy()
      sources[id] = nil
    end

--    -- Add a timeout source if idle for at least 3 seconds
--    if cur_state == "idle" then
--      -- honor "session.suspend-timeout-seconds" if specified
--      local timeout =
--          tonumber(node.properties["session.suspend-timeout-seconds"]) or 3

--      if timeout == 0 then
--        return
--      end

--      -- add idle timeout; multiply by 1000, timeout_add() expects ms
--      sources[id] = Core.timeout_add(timeout * 1000, function()
--        -- Suspend the node
--        Log.info(node, "was idle for a while; suspending ...")
--        node:send_command("Suspend")

--        -- Unref the source
--        sources[id] = nil

--        -- false (== G_SOURCE_REMOVE) destroys the source so that this
--        -- function does not get fired again after 3 seconds
--        return false
--      end)
--    end

  end)
end)

om:activate()

可能有比注释掉整个块更好的方法来做到这一点,但至少这种方式不会浪费处理时间来检查接收器的状态是否空闲。现在,在接收器闲置几秒钟后恢复播放音乐和视频时,不会出现烦人的音频延迟或爆音。我希望这对在 Fedora 35 上使用 WirePlumber 的人有所帮助。

答案3

我花了很多时间谷歌搜索并做这里描述的事情。

我将把整个算法留在这里(在 Ubuntu 23.04 上就像一个魅力)

  1. 将配置移至全局范围并更改其session.suspend-timeout-seconds参数:

    # Main config
     sudo mkdir -p /etc/wireplumber/main.lua.d
     sudo cp -a /usr/share/wireplumber/main.lua.d/50-alsa-config.lua /etc/wireplumber/main.lua.d/50-alsa-config.lua
    
     # Bluetooth config
     sudo mkdir -p /etc/wireplumber/bluetooth.lua.d/
     sudo cp -a /usr/share/wireplumber/bluetooth.lua.d/50-bluez-config.lua /etc/wireplumber/bluetooth.lua.d/50-bluez-config.lua
    
     # Change the needed settings in both config files
     # Pay attention to `--` in the beggining. It's a line comment in Lua. And we must remove it
     sudo sed -i 's/--\["session.suspend-timeout-seconds"\] = 5/\["session.suspend-timeout-seconds"\] = 0/g' /etc/wireplumber/main.lua.d/50-alsa-config.lua
     sudo sed -i 's/--\["session.suspend-timeout-seconds"\] = 5/\["session.suspend-timeout-seconds"\] = 0/g' /etc/wireplumber/bluetooth.lua.d/50-bluez-config.lua
    
  2. 然后重新加载服务:

    systemctl --user restart pipewire wireplumber
    
  3. 然后,您可以在播放和停止音频时通过此命令测试所有音频设备的状态,然后观察状态变化:

    watch -cd -n .1 pactl list short sinks
    

    它显示状态:

    • RUNNING — 设备当前正在播放或上次播放后不到 10 秒
    • IDLE — 设备未播放但准备立即播放(需要什么!)
    • 挂起 — 在此状态下,设备将延迟唤醒(不需要)

    会话中第一次播放后,不得再出现 SUSPENDED 状态。

恭喜!现在您的音频将无缝播放。

答案4

相关配置文件为/usr/share/wireplumber/main.lua.d/50-alsa-config.lua,但不要编辑它的系统版本

此解决方案不适用于蓝牙设备。要使其正常工作,请复制蓝牙文件并更改属性session.suspend-timeout-seconds

sudo cp -a /usr/share/wireplumber/bluetooth.lua.d/50-bluez-config.lua /etc/wireplumber/bluetooth.lua.d/50-bluez-config.lua

sudo vi /etc/wireplumber/bluetooth.lua.d/50-bluez-config.lua

50-bluez-config.lua:

apply_properties = {
  --["node.nick"] = "My Node",
  --["priority.driver"] = 100,
  --["priority.session"] = 100,
  --["node.pause-on-idle"] = false,
  --["resample.quality"] = 4,
  --["channelmix.normalize"] = false,
  --["channelmix.mix-lfe"] = false,
  ["session.suspend-timeout-seconds"] = 0,  -- 0 disables suspend
  --["monitor.channel-volumes"] = false,

  -- Media source role, "input" or "playback"
  -- Defaults to "playback", playing stream to speakers
  -- Set to "input" to use as an input for apps
  --["bluez5.media-source-role"] = "input",
},

相关内容