Skip to content

Instantly share code, notes, and snippets.

@git58
Last active February 2, 2026 12:46
Show Gist options
  • Select an option

  • Save git58/a679486ca253b0032025cc8c74770e9f to your computer and use it in GitHub Desktop.

Select an option

Save git58/a679486ca253b0032025cc8c74770e9f to your computer and use it in GitHub Desktop.
Fix viper4android on Manjaro KDE Plasma 6 (PipeWire)
#!/bin/bash
###############################################################################
# Viper4Linux Auto-Routing Supervisor Script
# ------------------------------------------
# This script performs three major tasks:
# 1. Creates and initializes the Viper4Linux audio processing pipeline.
# 2. Periodically monitors PipeWire routing and configuration changes.
# 3. Automatically restores correct audio links if PipeWire breaks them.
#
# The script is intended to run from KDE autostart without opening a terminal.
###############################################################################
# Short initial delay to allow PipeWire and PulseAudio compatibility layer to start.
sleep 2
###############################################################################
# 1. Ensure the virtual sink "viper" exists
###############################################################################
# Check if a sink named "viper" already exists.
# If not, create a null-sink that will act as the input for ViperFX.
if ! pactl list short sinks | grep -q "viper"; then
pactl load-module module-null-sink \
sink_name=viper \
sink_properties=device.description="Viper4Linux"
fi
# Set the newly created sink as the default sink and source.
# This reduces the chance of PipeWire auto-routing audio elsewhere.
pactl set-default-sink viper
pactl set-default-source viper.monitor
###############################################################################
# 2. Wait until the monitor source appears
###############################################################################
# PipeWire may take some time to register "viper.monitor".
# We wait until it becomes available before launching the processing pipeline.
while ! pactl list short sources | grep -q "viper.monitor"; do
sleep 0.2
done
###############################################################################
# 3. Kill any old gst-launch processes to avoid duplicates
###############################################################################
killall -9 gst-launch-1.0 2>/dev/null
###############################################################################
# 4. Load ViperFX parameters from config file
###############################################################################
CONFIG_FILE="$HOME/.config/viper4linux/audio.conf"
# If the config file exists, normalize whitespace and convert it into a single line.
# Example: "vb-gain = 800" → "vb-gain=800"
if [ -f "$CONFIG_FILE" ]; then
VIPER_PARAMS=$(sed -e 's/[[:space:]]*=[[:space:]]*/=/g' "$CONFIG_FILE" | tr '\n' ' ')
else
# Fallback parameters if no config file is found.
VIPER_PARAMS="fx-enable=true vb-enable=true vb-gain=800"
fi
###############################################################################
# 5. Start the audio processing pipeline
###############################################################################
# Launch gst-launch in the background:
# - pulsesrc reads from viper.monitor
# - viperfx applies audio effects
# - pulsesink outputs to the real hardware device
gst-launch-1.0 \
pulsesrc device=viper.monitor ! \
viperfx $VIPER_PARAMS ! \
pulsesink device="alsa_output.pci-0000_00_1f.3.analog-stereo" &
# Give gst-launch time to initialize its node in PipeWire.
sleep 1
###############################################################################
# 6. Function to restore correct PipeWire links
###############################################################################
restore_links() {
# This function re-establishes the correct audio routing.
# It is safe to call repeatedly; PipeWire will ignore duplicate links.
pw-link viper.monitor:monitor_FL viperfx:input_FL
pw-link viper.monitor:monitor_FR viperfx:input_FR
pw-link viperfx:output_FL alsa_output.pci-0000_00_1f.3.analog-stereo:playback_FL
pw-link viperfx:output_FR alsa_output.pci-0000_00_1f.3.analog-stereo:playback_FR
}
# Initial link restoration
restore_links
###############################################################################
# 7. Start the GUI
###############################################################################
# Launch the Viper4Linux GUI in the background.
viper4linux-gui &
###############################################################################
# 8. Background monitoring loop
###############################################################################
# This loop runs forever in the background and periodically checks:
# - Whether gst-launch is still running.
# - Whether the config file has changed.
# - Whether PipeWire links are still correct.
# - Whether viper.monitor still exists.
#
# If anything is wrong, the script automatically repairs it.
###############################################################################
# Save initial config checksum to detect changes.
LAST_CONF_HASH=$(md5sum "$CONFIG_FILE" 2>/dev/null | awk '{print $1}')
(
while true; do
###########################################################################
# Check if gst-launch is still running
###########################################################################
if ! pgrep -x "gst-launch-1.0" >/dev/null; then
# Restart the pipeline if it crashed or was killed.
gst-launch-1.0 \
pulsesrc device=viper.monitor ! \
viperfx $VIPER_PARAMS ! \
pulsesink device="alsa_output.pci-0000_00_1f.3.analog-stereo" &
sleep 1
restore_links
fi
###########################################################################
# Check if the config file has changed
###########################################################################
CURRENT_HASH=$(md5sum "$CONFIG_FILE" 2>/dev/null | awk '{print $1}')
if [ "$CURRENT_HASH" != "$LAST_CONF_HASH" ]; then
# Reload parameters and restart gst-launch with new settings.
LAST_CONF_HASH="$CURRENT_HASH"
killall -9 gst-launch-1.0 2>/dev/null
VIPER_PARAMS=$(sed -e 's/[[:space:]]*=[[:space:]]*/=/g' "$CONFIG_FILE" | tr '\n' ' ')
gst-launch-1.0 \
pulsesrc device=viper.monitor ! \
viperfx $VIPER_PARAMS ! \
pulsesink device="alsa_output.pci-0000_00_1f.3.analog-stereo" &
sleep 1
restore_links
fi
###########################################################################
# Check if PipeWire links are still correct
###########################################################################
# If any link is missing, restore all links.
if ! pw-link -l | grep -q "viper.monitor:monitor_FL.*viperfx:input_FL"; then restore_links; fi
if ! pw-link -l | grep -q "viperfx:output_FL.*analog-stereo:playback_FL"; then restore_links; fi
###########################################################################
# Check if viper.monitor still exists
###########################################################################
if ! pactl list short sources | grep -q "viper.monitor"; then
# Recreate the sink if PipeWire removed it.
pactl load-module module-null-sink \
sink_name=viper \
sink_properties=device.description="Viper4Linux"
pactl set-default-sink viper
pactl set-default-source viper.monitor
sleep 1
restore_links
fi
###########################################################################
# Sleep before next check
###########################################################################
sleep 3
done
) &
# End of script
@git58
Copy link
Author

git58 commented Feb 2, 2026

Changelog for v1.2

Viper4Linux Auto‑Routing Supervisor Script — Документация

Общее описание

Этот скрипт является автоматическим надзорным механизмом для аудиопайплайна Viper4Linux, работающего поверх PipeWire. Его задача — обеспечить стабильную работу цепочки:

Приложения → viper (null-sink) → viper.monitor → gst-launch → viperfx → ALSA

PipeWire иногда нарушает маршрутизацию, пересоздаёт узлы или сбрасывает соединения. Скрипт предотвращает такие сбои, автоматически восстанавливая корректные связи и перезапуская аудиопроцессинг при необходимости.

Скрипт предназначен для автозапуска в KDE Plasma и работает полностью в фоне, без открытия терминала.


Основные функции скрипта

1. Создание и инициализация виртуального sink viper

Скрипт проверяет, существует ли виртуальный sink с именем viper.
Если нет — создаёт его через module-null-sink.

Этот sink служит входной точкой для ViperFX.

Также скрипт устанавливает:

  • viper как default sink
  • viper.monitor как default source

Это уменьшает вероятность того, что PipeWire переназначит маршруты.


2. Ожидание появления viper.monitor

PipeWire может задерживать регистрацию монитор‑источника.
Скрипт ждёт, пока viper.monitor не появится, прежде чем запускать обработку звука.


3. Удаление старых процессов gst-launch

Перед запуском новой цепочки скрипт убивает все старые экземпляры gst-launch-1.0, чтобы избежать дублирования потоков.


4. Загрузка параметров ViperFX

Скрипт читает конфигурационный файл:

~/.config/viper4linux/audio.conf

и преобразует строки вида:

vb-gain = 800

в формат:

vb-gain=800

Если конфиг отсутствует — используются параметры по умолчанию.


5. Запуск аудиопайплайна через gst-launch

Скрипт запускает следующую цепочку:

pulsesrc (viper.monitor)
    → viperfx (с параметрами из конфига)
    → pulsesink (физическое ALSA‑устройство)

Запуск выполняется в фоне.


6. Восстановление PipeWire‑соединений

Функция restore_links() создаёт необходимые соединения:

  • viper.monitorviperfx
  • viperfx → ALSA‑sink

PipeWire игнорирует дубликаты, поэтому функция безопасна при повторных вызовах.


7. Запуск графического интерфейса Viper4Linux

GUI запускается в фоне и не влияет на работу пайплайна.


Фоновый мониторинг (основная логика скрипта)

Скрипт запускает бесконечный цикл, который каждые 3 секунды проверяет:


1. Жив ли процесс gst-launch

Если он упал:

  • запускается новый экземпляр
  • восстанавливаются PipeWire‑линки

2. Изменился ли конфигурационный файл

Скрипт вычисляет MD5‑хеш файла.

Если конфиг изменился:

  • gst-launch перезапускается
  • параметры обновляются
  • связи восстанавливаются

3. На месте ли PipeWire‑соединения

Если хотя бы одно соединение отсутствует — вызывается restore_links().


4. Существует ли viper.monitor

Если PipeWire удалил виртуальный sink:

  • создаётся новый viper
  • назначается default sink/source
  • восстанавливаются связи

Поведение при сбоях

Скрипт автоматически:

  • перезапускает аудиопайплайн
  • восстанавливает соединения
  • пересоздаёт виртуальный sink
  • обновляет параметры ViperFX
  • предотвращает неправильную маршрутизацию PipeWire

Он работает как самовосстанавливающийся сервис, но без systemd.


Преимущества данного решения

✔ Полностью автономен

Не требует systemd, работает из автозагрузки KDE.

✔ Самовосстанавливающийся

Любой сбой в пайплайне автоматически исправляется.

✔ Устойчив к изменениям PipeWire

PipeWire может пересоздавать узлы — скрипт это компенсирует.

✔ Минимальная задержка реакции

Проверка каждые 3 секунды.

✔ Безопасен

Не ломает существующие соединения, только восстанавливает нужные.


Когда использовать этот скрипт

Он идеально подходит для систем, где:

  • PipeWire часто сбрасывает соединения
  • ViperFX используется как постоянный аудиофильтр
  • требуется стабильная работа null‑sink → ViperFX → ALSA
  • пользователь не хочет вручную чинить граф в qpwgraph/helvum

@git58
Copy link
Author

git58 commented Feb 2, 2026

Фото схем со сломанным и рабочим соединением аудио

↓↓↓ Анализатор звукового тракта Helvum - звука нет ↓↓↓
helvum_bad

↓↓↓ Анализатор звукового тракта Helvum - звук есть ↓↓↓
helvum_good

↓↓↓ Анализатор звукового тракта qpwgraph - звука нет ↓↓↓
qpwgraph_bad

↓↓↓ Анализатор звукового тракта qpwgraph - звук есть ↓↓↓
qpwgraph_good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment