Add audio backend fix: DeckLink → ALSA + snd-aloop loopback

Resolve aborts on first launch on systems without a DeckLink card (default
Local.Audio.Type = DeckLink), and Resolve's audio engine retries forever
enumerating raw ALSA hardware when PipeWire owns every real card — the
"render queue stuck in progress with no output" hang.

Patches default-config.dat (and any existing user config.dat) to ALSA, then
loads snd-aloop as a virtual ALSA card PipeWire ignores, persists it via
/etc/modules-load.d/, and writes a PipeWire loopback bridge so monitor
audio remains audible during playback. Skip with RESOLVE_NO_ALOOP=1.

Ported from the Intel Arc installer where the fix was originally debugged.
This commit is contained in:
28allday 2026-05-01 13:52:23 +01:00
parent f387d84414
commit b9b8dbc6dc
2 changed files with 211 additions and 1 deletions

View file

@ -432,9 +432,120 @@ EOF
update-desktop-database "${HOME}/.local/share/applications" >/dev/null 2>&1 || true update-desktop-database "${HOME}/.local/share/applications" >/dev/null 2>&1 || true
sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true
# ==================== Audio backend fix (DeckLink → ALSA) ====================
#
# Resolve ships with `Local.Audio.Type = DeckLink` as the default in its
# system-wide config template at /opt/resolve/share/default-config.dat.
# That's correct for users with a Blackmagic DeckLink capture/playback card,
# but on systems without one Resolve aborts on first launch. Patch both the
# template (so future first-launches are correct) and any existing user
# config (so the current install isn't broken).
log "Switching Resolve audio backend default from DeckLink to ALSA..."
TEMPLATE=/opt/resolve/share/default-config.dat
if [[ -f "${TEMPLATE}" ]] && grep -q '^Local\.Audio\.Type = DeckLink$' "${TEMPLATE}"; then
sudo sed -i 's|^Local\.Audio\.Type = DeckLink$|Local.Audio.Type = ALSA|' "${TEMPLATE}"
log " Patched system template ${TEMPLATE}"
fi
USER_CFG="${HOME}/.local/share/DaVinciResolve/configs/config.dat"
if [[ -f "${USER_CFG}" ]] && grep -q '^Local\.Audio\.Type = DeckLink$' "${USER_CFG}"; then
cp "${USER_CFG}" "${USER_CFG}.bak.$(date +%s)"
sed -i 's|^Local\.Audio\.Type = DeckLink$|Local.Audio.Type = ALSA|' "${USER_CFG}"
log " Patched existing user config ${USER_CFG} (backup .bak.<timestamp> created)"
fi
# ==================== snd-aloop (the actual render-blocker fix) ====================
#
# Resolve's audio engine opens raw ALSA hardware via snd_pcm_open("hw:%d", ...)
# — it never goes through ALSA's plugin layer (default/pulse/pipewire) and it
# enumerates EVERY card under /dev/snd/controlC[0-32] looking for a usable PCM.
# When every real ALSA card on the system is owned/contested by PipeWire's
# session manager, Resolve's enumeration loops forever, the render queue
# never spawns the encoder, and the user sees:
# - alsa device meters "flickering" in wireplumber (each enumeration cycle
# briefly opens controlC*; PipeWire reacts)
# - render that "won't start" with no error in ResolveDebug.txt
# Confirmed via strace: 14000+ SNDRV_CTL_IOCTL_PCM_INFO ENXIO ioctls and
# 47000+ /dev/snd/controlCN ENOENT opens during the failed render attempt,
# concentrated AFTER the user clicks Render — i.e. a tight retry loop.
#
# THE FIX: load the kernel's snd-aloop module. It exposes a virtual ALSA
# loopback card that PipeWire ignores (no ACP profile, not auto-acquired).
# Resolve's enumerator finds it, can fully own it, settles on it, and the
# render proceeds. Side effect: a "Loopback" device shows up in alsamixer
# and pavucontrol — harmless.
#
# Skipped if RESOLVE_NO_ALOOP=1 (e.g. user already has a dedicated audio
# interface that Resolve uses). Persistent across reboots via
# /etc/modules-load.d/.
if [[ "${RESOLVE_NO_ALOOP:-0}" == "1" ]]; then
log "Skipping snd-aloop setup (RESOLVE_NO_ALOOP=1)"
else
log "Setting up snd-aloop (virtual ALSA card so Resolve render can start)..."
if ! lsmod | grep -qE '^snd_aloop'; then
if sudo modprobe snd-aloop 2>/dev/null; then
log " snd-aloop loaded for the current session"
else
warn " modprobe snd-aloop failed — kernel may lack the module."
warn " On Arch this is part of linux/linux-zen/linux-lts; verify: modinfo snd-aloop"
fi
else
log " snd-aloop already loaded"
fi
ALOOP_CONF=/etc/modules-load.d/snd-aloop.conf
if [[ ! -f "${ALOOP_CONF}" ]] || ! grep -qx 'snd-aloop' "${ALOOP_CONF}" 2>/dev/null; then
echo 'snd-aloop' | sudo tee "${ALOOP_CONF}" >/dev/null
log " Wrote ${ALOOP_CONF} (autoloads at boot)"
else
log " ${ALOOP_CONF} already configured"
fi
# Bridge snd-aloop capture → default sink so monitor audio is audible.
# Without this, Resolve writes to the loopback and the audio goes nowhere
# (loopback is a black hole until something captures the other side).
# The bridge is a PipeWire loopback module loaded from user config; it
# tracks the default sink so headphone/HDMI switching keeps working.
ALOOP_BRIDGE_DIR="${HOME}/.config/pipewire/pipewire.conf.d"
ALOOP_BRIDGE_FILE="${ALOOP_BRIDGE_DIR}/50-resolve-aloop-bridge.conf"
mkdir -p "${ALOOP_BRIDGE_DIR}"
if [[ ! -f "${ALOOP_BRIDGE_FILE}" ]]; then
cat > "${ALOOP_BRIDGE_FILE}" <<'EOF'
# DaVinci Resolve aloop monitor bridge — managed by Omarchy_resolve_v2.sh
# Bridges snd-aloop's capture side to the system default sink so Resolve's
# monitor audio is audible while editing. Without this, Resolve renders fine
# but you hear nothing during playback. Remove this file + restart PipeWire
# to disable.
context.modules = [
{ name = libpipewire-module-loopback
args = {
node.description = "DaVinci Resolve aloop monitor bridge"
capture.props = {
node.name = "resolve-aloop-capture"
target.object = "alsa_input.platform-snd_aloop.0.analog-stereo"
node.passive = true
}
playback.props = {
node.name = "resolve-aloop-playback"
media.class = "Stream/Output/Audio"
}
}
}
]
EOF
log " Wrote ${ALOOP_BRIDGE_FILE} (PipeWire loopback bridge)"
# Reload user PipeWire services so the new conf is picked up
if systemctl --user is-active --quiet pipewire 2>/dev/null; then
systemctl --user restart pipewire pipewire-pulse wireplumber 2>/dev/null || true
log " Reloaded user PipeWire services"
fi
else
log " ${ALOOP_BRIDGE_FILE} already in place"
fi
fi
echo echo
echo "✅ DaVinci Resolve installed to /opt/resolve" echo "✅ DaVinci Resolve installed to /opt/resolve"
echo " (vendor libc++ kept; libcrypt.so.1 ensured)" echo " (vendor libc++ kept; libcrypt.so.1 ensured; audio backend → ALSA + snd-aloop)"
echo " Launch from your app menu, or run: resolve-nvidia-open" echo " Launch from your app menu, or run: resolve-nvidia-open"
echo " Skip snd-aloop module setup: RESOLVE_NO_ALOOP=1 ./Omarchy_resolve_v2.sh"
echo " Logs: ~/.local/share/DaVinciResolve/logs/ResolveDebug.txt" echo " Logs: ~/.local/share/DaVinciResolve/logs/ResolveDebug.txt"
echo echo

View file

@ -97,6 +97,41 @@ Resolve doesn't support native Wayland. The wrapper script (`resolve-nvidia-open
- Installs udev rules for Blackmagic hardware (capture cards, control panels) - Installs udev rules for Blackmagic hardware (capture cards, control panels)
- Points all launchers at the XWayland wrapper - Points all launchers at the XWayland wrapper
### 7. Audio Backend Fix (DeckLink → ALSA + `snd-aloop`)
Two issues are fixed automatically:
**Default audio backend.** Resolve's shipped `default-config.dat` sets
`Local.Audio.Type = DeckLink`, which causes Resolve to abort on first launch
on systems without a Blackmagic DeckLink capture/playback card. The script
patches both the system template and any existing user config to use `ALSA`
(backing up the user config to `config.dat.bak.<timestamp>`).
**Render-blocker hang.** Resolve's audio engine opens raw ALSA hardware
(`hw:N`) and enumerates every card under `/dev/snd/control*`. When all real
ALSA cards are owned/contested by PipeWire's session manager, the
enumeration retries forever — the render queue never spawns the encoder, the
job sits at "in progress" with growing ETA, no output file appears, and
nothing useful lands in `ResolveDebug.txt`. `strace` shows tens of thousands
of `SNDRV_CTL_IOCTL_PCM_INFO` `ENXIO` ioctls per failed render.
The fix is to load the kernel's `snd-aloop` module. PipeWire ignores it (no
ACP profile, not auto-acquired), so Resolve can fully own it and the render
proceeds normally. The script:
- Runs `modprobe snd-aloop` for the current session
- Writes `/etc/modules-load.d/snd-aloop.conf` so it autoloads at boot
- Writes a PipeWire loopback bridge at
`~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf` so
monitor audio routes from the loopback's capture side to the system
default sink (without it, Resolve renders fine but you hear nothing
during playback; headphone/HDMI sink switching keeps working through
the bridge)
- Restarts user PipeWire services so the bridge loads immediately
Set `RESOLVE_NO_ALOOP=1` to skip this entirely (useful if you have a
dedicated audio interface Resolve already uses cleanly).
## Files Installed ## Files Installed
### Application ### Application
@ -145,6 +180,18 @@ By default, the script syncs the package database without upgrading. To include
RESOLVE_FULL_UPGRADE=1 ./Omarchy_resolve_v2.sh RESOLVE_FULL_UPGRADE=1 ./Omarchy_resolve_v2.sh
``` ```
### Skip the `snd-aloop` Audio Fix
If you have a dedicated audio interface (e.g. Focusrite Scarlett, MOTU, etc.)
that Resolve already uses cleanly, you don't need the virtual loopback card:
```bash
RESOLVE_NO_ALOOP=1 ./Omarchy_resolve_v2.sh
```
This skips the `modprobe snd-aloop`, the `/etc/modules-load.d/` entry, and
the PipeWire loopback bridge. The DeckLink → ALSA config patch still runs.
### Hybrid GPU Laptops (Optimus) ### Hybrid GPU Laptops (Optimus)
If you have an Intel iGPU + NVIDIA dGPU, edit the wrapper to force Resolve onto the NVIDIA GPU: If you have an Intel iGPU + NVIDIA dGPU, edit the wrapper to force Resolve onto the NVIDIA GPU:
@ -180,6 +227,53 @@ Stale lockfiles from a previous crash. The wrapper clears these automatically, b
rm -f /tmp/qtsingleapp-DaVinci* rm -f /tmp/qtsingleapp-DaVinci*
``` ```
### Render queue says "in progress" forever, no output file
This is the audio render-blocker hang — Resolve's audio engine is stuck
enumerating ALSA cards. Confirm `snd-aloop` is loaded:
```bash
lsmod | grep snd_aloop
```
If absent, load it and retry:
```bash
sudo modprobe snd-aloop
```
If you ran the installer with `RESOLVE_NO_ALOOP=1` and want to opt back in,
re-run the installer without that variable, or do it manually:
```bash
sudo modprobe snd-aloop
echo 'snd-aloop' | sudo tee /etc/modules-load.d/snd-aloop.conf
```
If `lsmod` shows `snd_aloop` is loaded but renders still hang, check the
clip codec with `ffprobe` — ProRes RAW will hang silently on Linux without
Apple's ProRes RAW SDK plugins, which is a separate issue from this audio
fix.
### No audio during playback / monitor sink switches don't work
The PipeWire loopback bridge at
`~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf` routes
the snd-aloop capture side to your default sink. If headphone/HDMI
switching stops working for Resolve playback, restart user PipeWire
services:
```bash
systemctl --user restart pipewire pipewire-pulse wireplumber
```
To remove the bridge entirely:
```bash
rm ~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf
systemctl --user restart pipewire pipewire-pulse wireplumber
```
### Missing library errors ### Missing library errors
Re-run the installer — it will re-patch RPATH and re-check dependencies: Re-run the installer — it will re-patch RPATH and re-check dependencies:
@ -233,6 +327,11 @@ sudo rm -f /usr/lib/udev/rules.d/99-BlackmagicDevices.rules
sudo rm -f /usr/lib/udev/rules.d/99-ResolveKeyboardHID.rules sudo rm -f /usr/lib/udev/rules.d/99-ResolveKeyboardHID.rules
sudo rm -f /usr/lib/udev/rules.d/99-DavinciPanel.rules sudo rm -f /usr/lib/udev/rules.d/99-DavinciPanel.rules
# Remove the snd-aloop autoload entry + PipeWire bridge (optional)
sudo rm -f /etc/modules-load.d/snd-aloop.conf
rm -f ~/.config/pipewire/pipewire.conf.d/50-resolve-aloop-bridge.conf
systemctl --user restart pipewire pipewire-pulse wireplumber
# Remove user data (WARNING: deletes all projects and settings) # Remove user data (WARNING: deletes all projects and settings)
rm -rf ~/.local/share/DaVinciResolve rm -rf ~/.local/share/DaVinciResolve