Skip to content

Instantly share code, notes, and snippets.

@h4rm0n1c
Last active August 14, 2025 16:59
Show Gist options
  • Save h4rm0n1c/650c0ec6dafaa0b37698735a0f171c73 to your computer and use it in GitHub Desktop.
Save h4rm0n1c/650c0ec6dafaa0b37698735a0f171c73 to your computer and use it in GitHub Desktop.
An init.d style vban reciever script

Needs: screen, pipewire, JACK, pw-jack, vban_receptor does not use fifo buffers or pipes or other old stuff, just audio in from vban and audio out to local pipewire sinks. I have used this for mic passthrough from windows to a linux OBS streaming setup without issue.

15/08/2025: improved, mono mode. in voicemeeter you're gonna want to set 48000hz 24 bit PCM and 1 channel, default stream name is rawmic

#!/bin/sh
SCREEN_NAME=vban_mic
VBAN_SOURCE_NAME=rawmic
VBAN_HOST=10.0.0.1
VBAN_PORT=6980
SINK_NAME=VBAN_Sink
SINK_DESC="VBANSink"
SOURCE_NAME=VBAN_Mic
SOURCE_DESC="VBANMic"
ensure_pipewire_ready() {
i=0
while [ $i -lt 5 ]; do
if pw-cli ls Core >/dev/null 2>&1; then return 0; fi
sleep 1
i=$((i+1))
done
echo "Warning: PipeWire may not be ready yet." >&2
}
ensure_virtual_devices() {
# Create a dedicated null sink (mono, 48k) if not present
if ! pactl list short sinks | awk '{print $2}' | grep -qx "$SINK_NAME"; then
pactl load-module module-null-sink \
sink_name="$SINK_NAME" \
sink_properties="device.description=$SINK_DESC" \
rate=48000 channels=1 >/dev/null
fi
# Create a mic from the sink's monitor (mono) if not present
if ! pactl list short sources | awk '{print $2}' | grep -qx "$SOURCE_NAME"; then
pactl load-module module-remap-source \
master="${SINK_NAME}.monitor" \
source_name="$SOURCE_NAME" \
source_properties="device.description=$SOURCE_DESC" \
rate=48000 channels=1 >/dev/null
fi
}
# Resolve the mono playback port name for our sink (playback_MONO or playback_FL)
_get_sink_playback_port() {
# Look for a port that starts with "<SINK_NAME>:playback_"
pw-link -l 2>/dev/null | awk -v s="$SINK_NAME" '
$1 ~ "^" s ":playback_" { print $1 }' | head -n1
}
link_vban_to_sink() {
# Wait for VBAN to appear
tries=0
while [ $tries -lt 40 ]; do
if pw-link -l 2>/dev/null | grep -q '^vban:playback_1$'; then
break
fi
sleep 0.25; tries=$((tries+1))
done
# Disconnect VBAN from anything else
pw-link -l 2>/dev/null | awk '
$1=="vban:playback_1" && $2=="|->" { print $3 }
$1=="vban_receptor:playback_1" && $2=="|->" { print $3 }
' | while read -r dest; do
pw-link -d "vban:playback_1" "$dest" 2>/dev/null || true
pw-link -d "vban_receptor:playback_1" "$dest" 2>/dev/null || true
done
# Link directly to your known mono mic input
TARGET_IN="input.VBAN_Mic:input_MONO"
pw-link "vban:playback_1" "$TARGET_IN" 2>/dev/null || \
pw-link "vban_receptor:playback_1" "$TARGET_IN" 2>/dev/null || {
echo "Error: failed to link VBAN playback_1 → ${TARGET_IN}" >&2
return 1
}
echo "Linked VBAN → ${TARGET_IN}"
}
start() {
echo "Starting VBAN audio service (JACK via PipeWire)…"
# Clean any previous VBAN screen
screen -S "$SCREEN_NAME" -X quit 2>/dev/null
# Make sure PipeWire is up and create persistent devices
ensure_pipewire_ready
ensure_virtual_devices
# Launch vban_receptor through pw-jack (don’t try to spawn a real jackd)
if ! command -v pw-jack >/dev/null 2>&1; then
echo "Error: pw-jack not found. Install pipewire-jack." >&2
return 1
fi
echo "Launching vban_receptor…"
screen -dmS "$SCREEN_NAME" \
env JACK_NO_START_SERVER=1 pw-jack \
vban_receptor -i "$VBAN_HOST" -p "$VBAN_PORT" -s "$VBAN_SOURCE_NAME" -b jack --channels=1
# Wire VBAN to the sink, which feeds the persistent mic
link_vban_to_sink
echo "VBAN service started."
echo "→ Mic available to apps as: $SOURCE_DESC ($SOURCE_NAME)"
}
stop() {
echo "Stopping VBAN audio service…"
screen -S "$SCREEN_NAME" -X quit
echo "VBAN receiver stopped. (Virtual mic/sink left in place.)"
}
purge() {
echo "Stopping and removing virtual devices…"
stop
# Unload remap-source and null-sink modules associated with our names
pactl list short modules | grep -E "module-(remap-source|null-sink)" | \
grep -E "$SINK_NAME|$SOURCE_NAME" | awk '{print $1}' | while read -r MID; do
pactl unload-module "$MID"
done
echo "Purged VBAN virtual devices."
}
status() {
printf "%-50s" "Checking VBAN receiver…"
if screen -list 2>/dev/null | grep -q "[.]$SCREEN_NAME"; then
echo "Running"
else
echo "Not running"
fi
# Show presence of our virtual devices
pactl list short sinks | awk '{print $2}' | grep -qx "$SINK_NAME" && echo "Sink: $SINK_NAME present" || echo "Sink: $SINK_NAME missing"
pactl list short sources | awk '{print $2}' | grep -qx "$SOURCE_NAME" && echo "Source: $SOURCE_NAME present" || echo "Source: $SOURCE_NAME missing"
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 1; start ;;
status) status ;;
purge) purge ;;
*)
echo "Usage: $0 {start|stop|restart|status|purge}"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment