Skip to content

Instantly share code, notes, and snippets.

@bradkovach
Last active June 4, 2021 17:16
Show Gist options
  • Save bradkovach/cec0a1962adece726d2ad7ffca0e88f9 to your computer and use it in GitHub Desktop.
Save bradkovach/cec0a1962adece726d2ad7ffca0e88f9 to your computer and use it in GitHub Desktop.
PulseAudio script to allow Discord/etc to capture application audio AND microphone without microphone echo
#!/bin/bash
# Acknowledgements
# This script made heavy use of the guide at https://www.reddit.com/r/discordapp/comments/f22vz6/guide_how_to_stream_audio_to_discord_on_linux/
# and also the guide at https://endless.ersoft.org/pulseaudio-loopback/
# Gotchas
# The Discord app does not let me select the V1 input directly, so I have to use pavucontrol to change the input device *outside* of Discord
# The name of the input will not update within discord, but it should work properly.
# Microphone/Input Configuration
# To find this value, open Discord so it is listening to you on the AV test page so the source is running
# as discord has the source open, run `pactl list sources` and then look for
# Source #[ANY NUMBER]
# State: RUNNING
# Name: [NAME OF MIC] <----------(Copy this into the quotes below)
# `… a bunch of other junk …`
INPUT="alsa_input.usb-GN_Netcom_A_S_Jabra_PRO_930_0320D4187805-00.mono-fallback"
# Playback Configuration
# To find this value, play media so that audio is coming through your desired speaker.
# While the music is playing, run `pactl list sinks`
# Sink #[ANY NUMBER]
# State: RUNNING
# Name: [NAME OF OUTPUT] <----------(Copy this into the quotes below)`
# `… a bunch of other junk …`
OUTPUT="alsa_output.usb-GN_Netcom_A_S_Jabra_PRO_930_0320D4187805-00.mono-fallback"
# Virtual Sink Configuration
# You do not need to adjust these, but if there are values that make more sense to you, use them.
# These names correspond to the helpful guide/diagram here https://endless.ersoft.org/pulseaudio-loopback/
# games => v2
# v2 => v1
# v2 => output
# input => v1
# streaming app => output
V1_NAME="v1"
V2_NAME="v2"
# Sanity Checks
# If the script attempt to setup virtual sinks with non-existent sources or outputs, you may lose sound until
# you log out or reboot. This will make sure the specified $INPUT and $OUTPUT actually exist before proceeding.
N_SOURCES=$(pactl list sources | grep -c "Name: $INPUT")
N_SINKS=$(pactl list sinks | grep -c "Name: $OUTPUT")
if [ "$N_SOURCES" -ne "1" ]; then
echo "Input '$INPUT' not found in PulseAudio sources! Found $N_SOURCES sources. Check configuration and try again."
exit 1
fi
if [ "$N_SINKS" -ne "1" ]; then
echo "Output '$OUTPUT' not found in PulseAudio sinks! Found $N_SINKS sinks. Check configuration and try again."
exit 1
fi
# we need two virtual sinks to accomplish streaming with no microphone echoing into your ear
V1_NUMBER=$(pactl load-module module-null-sink sink_name=$V1_NAME sink_properties=device.description=$V1_NAME)
V2_NUMBER=$(pactl load-module module-null-sink sink_name=$V2_NAME sink_properties=device.description=$V2_NAME)
# connect input to V1
LO_MIC_TO_V1=$(pactl load-module module-loopback sink=$V1_NAME source=$INPUT)
# connect v2 to output
LO_V2_TO_OUTPUT=$(pactl load-module module-loopback sink=$OUTPUT source=$V2_NAME.monitor )
# connect v2 to v1
LO_V2_TO_V1=$(pactl load-module module-loopback sink=$V1_NAME source=$V2_NAME.monitor)
# Leave the terminal running at this step and then press enter when you're done
# streaming/recording to reset your sound settings.
read -p "Press enter to destroy virtual sinks and loopbacks"
# disconnect the loopbacks
pactl unload-module $LO_V2_TO_V1
pactl unload-module $LO_V2_TO_OUTPUT
pactl unload-module $LO_MIC_TO_V1
# destroy the sinks
pactl unload-module $V2_NUMBER
pactl unload-module $V1_NUMBER
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment