discord-haskell-voice: Voice support for discord-haskell.

[ discord, library, mit, network, program, udp ] [ Propose Tags ]
Versions [RSS] 2.2.0, 2.2.1, 2.2.2, 2.3.0, 2.3.1
Change log ChangeLog.md
Dependencies aeson (==, async (>=2.2.3 && <2.4), base (>=4.7 && <5), binary (>=0.8 && <0.9), BoundedChan (==, bytestring (>= && <0.11), conduit (==, discord-haskell (>=1.12.0 && <=1.14.0), discord-haskell-voice, microlens (>=, microlens-th (>=, mtl (==2.2.2), network (>= && <3.2), optparse-applicative (>= && <0.17), opus (==, process (>= && <1.7), safe-exceptions (>= && <0.1.8), saltine (>= && <0.2), stm (>= && <2.5.1), stm-containers (==1.2), text (>= && <2), time (>=1.9.3 && <=1.13), unliftio (>=0.2.18 && <0.3), websockets (>= && <0.12.8), wuss (>=1.1.18 && <=1.2) [details]
License MIT
Copyright 2021-2022 Yuto Takano
Author Yuto Takano
Maintainer moa17stock@gmail.com
Category Network
Home page https://github.com/yutotakano/discord-haskell-voice#readme
Bug tracker https://github.com/yutotakano/discord-haskell-voice/issues
Source repo head: git clone https://github.com/yutotakano/discord-haskell-voice
Uploaded by yutotakano at 2022-07-03T18:00:29Z
Executables join-all-on-start, basic-music-bot
Downloads 342 total (13 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for discord-haskell-voice-2.3.1

[back to package description]


hackage version discord-haskell version dependency

Welcome to discord-haskell-voice! This library provides you with a high-level interface for interacting with Discord's Voice API, building on top of the discord-haskell library by Karl.

For a quick intuitive introduction to what this library enables you to do, see the following snippet of code:

rickroll :: Channel -> DiscordHandler ()
rickroll c@(ChannelVoice {}) = do
    void $ runVoice $ do
        join (channelGuild c) (channelId c)
        playYouTube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

The library actively uses and supports conduit, which enables you to write something like the following as well!

rickrollHalfVolume :: Channel -> DiscordHandler ()
rickrollHalfVolume c@(ChannelVoice {}) = do
    void $ runVoice $ do
        join (channelGuild c) (channelId c)
        let halfAmplitude = awaitForever $ \current ->
                yield $ round $ fromIntegral current * 0.5
        playYouTube' "rickroll" $ packInt16C .| halfAmplitude .| unpackInt16C
        liftIO $ print "finished playing!"


  • The library uses saltine for encryption and decryption of audio packets. This requires libsodium to be installed on your system. See their README for information.
  • The library requires Opus libraries to be installed on your system. The libopus-dev package available on package repositories should be sufficient on most *nix systems. The opus brew package suffices on Mac. Windows is unexplored yet (WSL works).
  • If you are to use any variants of playFile, playYouTube, you will need FFmpeg installed. To specify a custom executable name, see the -With function variants.
  • If you are to use any variants of playYouTube, you will additionally need youtube-dl installed. This is used to get the stream URL to pass to FFmpeg. To specify a custom executable name (such as yt-dlp), use playYouTubeWith.


What is supported:

  • Can join/leave Discord voice channels. It is possible to join multiple of them simultaneously (one per sever) and stream different contents to each.
  • It is also possible to join many voice channels (across many servers) and play the same content, radio/subscriber-style.
  • You can play arbitrary PCM audio, arbitrary audio (with FFmpeg), and arbitrary internet audio (with youtube-dl).
  • You can transform audio arbitrarily using Conduit.
  • As it streams content, the library /should/ use constant memory (unverified).
  • OPUS encoding and specific implementation details such as handshakes and encryption are done opaquely, and a nice abstraction layer is provided.

What is not supported:

  • Decrypting audio packets sent from Discord (other people's voices), and decoding them to PCM.

See examples/BasicMusicBot.hs for a bot that uses many advanced features of the library, including dynamically adjusting the stream audio using a TVar (and allowing users to change the TVar using a /volume command).


This library is available on Hackage, at https://hackage.haskell.org/package/discord-haskell-voice.


To use it in your Cabal-based project, add discord-haskell-voice as a dependency in your .cabal file:

# --- myproject.cabal <truncated>
      base >=4.7 && <5
    , discord-haskell ==1.14.0
    , discord-haskell-voice ==2.3.1


To use it in your Stack-based project, add discord-haskell-voice in both your package.yaml and stack.yaml files (since this library is not available in Stackage for the same reason discord-haskell is not on Stackage)

# --- stack.yaml <truncated>
- discord-haskell-1.14.0
- discord-haskell-voice-2.3.1
# --- package.yaml <truncated>
- base >= 4.7 && < 5
- discord-haskell == 1.14.0
- discord-haskell-voice == 2.3.1


See the Haddock documentation on the Hackage page, at https://hackage.haskell.org/package/discord-haskell-voice/docs/Discord-Voice.html.

Future Plans

  • Use stm-conduit and stm for a safer Chan?
  • Look into SubprocessException seemingly never been thrown (e.g. when SIGINT is signalled to the libarry while FFmpeg is running)
  • Consider, document, and improve the distinction of errors (VoiceError) vs exceptions, and note down why any choices are made