3

In Fedora 35, WirePlumber has replaced pipewire-media-session as the audio session manager. There is a highly annoying problem with audio on many built-in soundcards on Linux where the audio sink is suspended after nothing is played for 3 seconds. Upon resuming playback after 3 seconds have passed, audio is delayed or pops in. How do we fix this default behavior?

3 Answers3

12

The relevant configuration file is /usr/share/wireplumber/main.lua.d/50-alsa-config.lua, but don't edit the system version of it!

You need to copy it into /etc/wireplumber/main.lua.d/ (global config) or ~/.config/wireplumber/main.lua.d/ (user config) and make the necessary changes.

The easiest way is to copy it into the global config location so that it applies to all user accounts:

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

You then need to scroll down to the bottom of the file, inside the apply_properties section, and add a line there which says:

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

I've done a lot more changes and customized it for my own personal hardware. Here's my configuration for reference, but this config is only useful for my exact devices. You actually only need the line above to disable the auto-suspend. Add it to your own default config. Do not copy my config. The other changes I've made are unrelated.

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
    }
  }
}

Setting the session.suspend-timeout-seconds property to 0 prevents the suspension/sleep behavior. It completely disables the behavior, as can be seen in WirePlumber's source code.

WirePlumber has to be restarted in order for changes to take effect:

systemctl --user restart wireplumber
2

This is normally fixed in systems running PipeWire without WirePlumber that use pipewire-media-session by changing session.suspend-timeout-seconds to 0 in the bottom section of /etc/pipewire/media-session.d/alsa-monitor.conf. However, this directory or any session monitor configuration file is not found within Fedora 35 installations. There is virtually no documentation showing how to prevent sinks from suspending in 3 seconds, so I had to figure this one out by myself. Instead, we have to modify a Lua script within a script directory for WirePlumber. Navigate to /usr/share/wireplumber/scripts/ and make a backup copy of suspend-node.lua. Then open suspend-node.lua in a text editor or the terminal using sudo privileges, and comment out the code block that is responsible for sink timeout and suspending sinks, so that the file looks like the following:

-- 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()

There may be a better way to do this than commenting out the whole block, but at least this way processing time isn't wasted checking if the state of the sink is idle. Now, there's no annoying audio delay or pop when resuming playback of music and videos after the sink has been idle for several seconds. I hope this was helpful to those people using WirePlumber on Fedora 35.

0

The relevant configuration file is /usr/share/wireplumber/main.lua.d/50-alsa-config.lua, but don't edit the system version of it

This solution does not work for bluetooth devices. To make it work copy the bluetooth file and change the property 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",
},