Tool to pipe raw audio to Discord via a bot. Input data must be PCM 32-bit floating-point little-endian (aka f32le
).
If your audio is in any other format, it is possible to use tools like ffmpeg to convert it to the required format.
ffmpeg -re -i sample.mp3 -map 0:a:0 -c:a:0 pcm_f32le -ar 48000 -ac 2 -f f32le - | stdinman
stdinman_vinyl_2.mp4
There are several interesting discord bots and such floating around, such as for playing Youtube links, soundcloud etc. There are also ways to make your Mic input some kind of loopback device to play audio via your own user. However, as an Arch Linux user, I wanted something super composable - the ability to play any raw audio into Discord, via a bot.
That's exactly what this program does. It is entirely up to the user how they wish to prepare the audio source - for instance their microphone, their speaker output (i.e. alsa monitor), an internet audio stream (or anything that can be passed into ffmpeg), or spinning vinyl. Check out the recipes section for more.
Ensure you have the rust toolchain installed, for e.g. via rustup. Then, you can install the binary via cargo:
cargo install --git https://github.com/ckcr4lyf/stdinman.git
I've mostly only tested it on Linux, but it should work on Mac as well, and probably on Windows via WSL.
stdinman works via a Discord Bot, connected to a Voice Channel. You must ensure this bot is:
- added to the server where you want to stream audio
- has the "Connect" & "Speak" voice permissions
There is a guide at the bottom on setting up a Discord Bot if you're unfamiliar.
You'll need to provide the bot's token, and the ID of the voice channel you want it to connect to. These can be passed via CLI args:
stdinman --bot-token [BOT_TOKEN] --voice-channel-id [VOICE_CHANNEL_ID]
Alternatively, just run stdinman
once, and it will generate a config file in $XDG_CONFIG_HOME/stdinman/stdinman.toml
, where you can store the bot token & voice channel id.
Now just pipe audio to stdinman! Check out the recipes section for some examples.
Logging can be configured via an environment variable: export RUST_LOG=stdinman=DEBUG
The recipes involving pactl are intended for use on linux with PulseAudio (or Pipewire with the Pulseaudio shim). Examples with ffmpeg could be used on Mac as well.
ffmpeg is an amazing A/V utility, that can handle an incredible amount of input formats. If you can pass audio from a source into ffmpeg, or even a video (assuming you only want the audio), you can configure it to output the audio as 32-bit floating point PCM, which can then be piped to stdinman
and streamed to Discord.
You should use the -re
flag on the input, to ensure ffmpeg consumes it in real time.
ffmpeg -re -i sample.mp3 -map 0:a:0 -c:a:0 pcm_f32le -ar 48000 -ac 2 -f f32le - | stdinman
Using the incredible work by the people over at librespot , it is possible to create a "Spotify Connect" device your account can play audio to, who's output can be piped to another program.
Using ffmpeg
in the middle to ensure the format matches, we can then pipe it over to stdinman
and stream it straight to Discord!
librespot -n stdinman_connect --backend pipe -b 320 | ffmpeg -f s16le -ac 2 -ar 44100 -re -i pipe:0 -map 0:a:0 -c:a:0 pcm_f32le -ar 48000 -ac 2 -f f32le - | stdinman
For more information on how to use librespot check out their repo.
Note: Using librespot is probably forbidden by Spotify.
Note: If you're in the VC on the same computer, you would hear a kind of "echo" on the audio - first your headphones / speakers, and then the audio from discord with some latency. In such situations, it is recommended to output the audio to a virtual sink, and then play that via the bot (see the next recipe). This has the additional advantage of sharing a specific application's audio instead of the whole system.
You can use pactl
to view the monitor input corresponding to your speakers:
$ pactl list short sources
77 alsa_output.pci-0000_00_1f.3.3.analog-stereo.monitor PipeWire s32le 2ch 48000Hz SUSPENDED
78 alsa_input.pci-0000_00_1f.3.3.analog-stereo PipeWire s32le 2ch 48000Hz SUSPENDED
In this case, alsa_output.pci-0000_00_1f.3.3.analog-stereo.monitor
is the speakers' monitor. To use it with stdinman:
parec -d alsa_output.pci-0000_00_1f.3.3.analog-stereo.monitor --format=float32le --rate=48000 | stdinman
This would route all audio from the app to the virtual sink, who's monitor you can then pass to stdinman
to stream to Discord.
To do this, we first need to create a virtual sink via pactl
. You can replace stdinman-demo
with whatever name you want.
pactl load-module module-null-sink media.class=Audio/Sink sink_name=stdinman-demo channel_map=left,right
Then, using some GUI like pavucontrol
, set the output of the program to this new sink:
(Note: you won't be able to hear this application on your normal speakers anymore)
Then, use this sink's monitor with parec
and pass the output to stdinman!
parec -d stdinman-demo.monitor --format=float32le --rate=48000 | stdinman
Many thanks to Enitoni for pulseshitter, which was my inspiration for this project.
Also thanks to the amazing developers of serenity & songbird , for making working with Discord bots and streaming audio in Rust so easy.
Log into your Discord account in your browser, and then go to their developer portal: https://discord.com/developers/applications .
Next create a "new application", and give it any name you want.
In the "App Management" page, click on "Bot", then click "Reset Token"
Copy this token somewhere, this is needed for stdinman
to authenticate as the bot.
From the same developer portal, we will generate an invite link. Click "OAuth2", then "URL Generator". In the "Scopes" section, select "bot", and then in "Bot Permissions", select "Connect" and "Speak", and then copy the URL. You can now use this URL to invite the bot to your server.
In your server, go to the hover over the voice channel an click on "Open Chat". The Channel ID is the second number in the URL.
Alternatively, enable "Developer Mode" under Advanced settings in your Discord account, then you can just right-click the voice channel and copy the ID.