Discord Social gives a lobby a voice call. The Toolkit can play the other people either straight through the system’s output device, or through Unity AudioSources so a voice can come from a position in the world.
Two ways to hear people #
Device (default) | UnityAudio | |
|---|---|---|
| What happens | Discord plays everyone through the output device, like a normal call | Each person plays through an AudioSource you choose |
| Positional sound | No | Yes, with the AudioSource’s own 3D settings |
| Unity AudioMixer, filters, reverb zones | No | Yes |
| Setup | None | A DiscordVoiceSource on each person’s GameObject, bound to that person |
| Chosen | DiscordLobbySession.VoiceOutput, before Join voice | the same |
The choice applies to the next call. Change it before joining, not during a call. DiscordVoiceOutputToggle is a ready-made switch, and it is disabled while you are in voice.
Joining and leaving #
DiscordLobbySession.JoinVoice() joins the current lobby’s call, and LeaveVoice() leaves it. InVoice and OnVoiceChanged report the state. Leaving the lobby also ends the call. DiscordVoiceBar puts join or leave, mute and deafen on three buttons.
Voice from a character (3D voice) #
- Set the lobby session’s voice output to Unity Audio (the Inspector field, the toggle, or
session.VoiceOutput = DiscordVoiceOutput.UnityAudio). - On each player’s pawn or avatar prefab add an AudioSource and a DiscordVoiceSource. On the AudioSource set Spatial Blend to 1 and choose the rolloff, minimum distance and maximum distance as for any other sound.
- When you spawn a pawn for a player, call
voiceSource.Bind(userData)with that player’s Discord user. In the Demo Game,DemoSessionStagedoes this for every lobby member. - Skip the local player. You do not receive your own voice, so your own pawn needs no source.
Then press Join voice. Each remote player’s voice plays from their pawn, and gets quieter and pans as they move.
What you hear if you skip a step #
- A person with no bound
DiscordVoiceSourceis still heard through the output device. SetDiscordVoiceRouter.MuteUnrouted = trueto silence them instead. - A person bound to a source is muted on the device, so nobody is heard twice.
- If the lobby session is on
Device, sources stay silent and everyone plays through the device.
How it works #
DiscordLobbySession starts the call with DiscordSocialApp.StartCallWithAudio, which hands the game each participant’s audio as 16 bit samples on the SDK’s audio thread. DiscordVoiceRouter.OnAudioReceived mixes the audio down to mono, queues it in a small buffer per person, and sets the callback’s mute flag for people it will play. A DiscordVoiceSource creates a streaming AudioClip at the incoming sample rate (Discord uses 48 kHz) and plays it on its AudioSource, reading from that buffer.
The buffer holds about 60 ms before it starts and at most half a second. If the speaker’s audio arrives faster than it plays, the oldest audio is dropped so the voice does not fall behind. If it runs dry, the source plays silence and rebuffers.
Code #
// 3D voice for a spawned pawn
var source = pawn.GetComponentInChildren<DiscordVoiceSource>();
source.Bind(new UserData(discordUserId)); // or source.Bind(userData)
// Choose the output before joining
session.VoiceOutput = DiscordVoiceOutput.UnityAudio;
session.JoinVoice();
DiscordSocialApp.StartCallWithAudio(lobbyId, received, captured) in Foundation for Discord Social is the underlying call if you want the audio for something else. Its handlers run on the audio thread: do not touch Unity objects from them, and copy the samples if you keep them, because the array is reused. captured receives your own microphone audio before it is processed.
The other voice components #
| Component | Does |
|---|---|
DiscordVoiceBar | Join or leave voice, mute and deafen buttons whose labels show the next action |
DiscordVoiceParticipantList, DiscordVoiceParticipantRow | Everyone in the call: a speaking light, a muted marker, a local mute toggle and a volume slider |
DiscordVoiceSettingsPanel | Microphone and speaker pickers, volumes, input mode, noise suppression, echo cancellation, automatic gain and Krisp noise cancellation |
DiscordPushToTalkButton | Opens the microphone while held. For a key, call DiscordSocialApp.SetPushToTalkActive from your own input handling |
Platform notes #
- macOS: set the
NSMicrophoneUsageDescriptionkey in the app’s Info.plist. - iOS: enable the background audio mode in the Info.plist. Discord’s own Unity sample has a post-build processor that does this.
- Android: the app needs the
RECORD_AUDIOpermission. - Flatpak Discord on Linux: the SDK does not find the desktop client’s IPC socket there. Sign in, calls and voice still work, but the noise, echo and gain switches cannot show their current state.
Verified and not verified #
Run against live Discord on one account: joining and leaving a lobby call, the participant list, mute, deafen, volumes, input mode, push to talk state, the device lists, and the microphone audio callback delivering 48 kHz mono audio. The buffer and router logic has unit tests. Not yet run: playing another person’s voice through an AudioSource (positional playback), the speaking light, and device switching during a call. Those need a second account.