discord-haskell-voice-2.3.1: Voice support for discord-haskell.
Copyright(c) Yuto Takano (2021)
LicenseMIT
Maintainermoa17stock@gmail.com
Safe HaskellNone
LanguageHaskell2010

Discord.Internal.Voice

Description

WARNING

This module is considered internal.

The Package Versioning Policy does not apply.

The contents of this module may change in any way whatsoever and without any warning between minor versions of this package.

Description

This module is the internal entry point into discord-haskell-voice. Any use of this module (or other Internal modules) is discouraged. Please see Discord.Voice for the public interface.

Synopsis

Documentation

liftDiscord :: DiscordHandler a -> Voice a Source #

liftDiscord lifts a computation in DiscordHandler into a computation in Voice. This is useful for performing DiscordHandler actions inside the Voice monad.

Usage:

runVoice $ do
    join (read "123456789012345") (read "67890123456789012")
    liftDiscord $ void $ restCall $ R.CreateMessage (read "2938481828383") "Joined!"
    liftIO $ threadDelay 5e6
    playYouTube "Rate of Reaction of Sodium Hydroxide and Hydrochloric Acid"
    liftDiscord $ void $ restCall $ R.CreateMessage (read "2938481828383") "Finished!"
void $ restCall $ R.CreateMessage (read "2938481828383") "Finished all voice actions!"

runVoice :: Voice () -> DiscordHandler (Either VoiceError ()) Source #

Execute the voice actions stored in the Voice monad.

A single mutex and sending packet channel is used throughout all voice connections within the actions, which enables multi-channel broadcasting. The following demonstrates how a single playback is streamed to multiple connections.

runVoice $ do
    join (read "123456789012345") (read "67890123456789012")
    join (read "098765432123456") (read "12345698765456709")
    playYouTube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

The return type of runVoice represents result status of the voice computation. It is isomorphic to Maybe, but the use of Either explicitly denotes that the correct/successful/Right behaviour is (), and that the potentially- existing value is of failure.

This function may propagate and throw an IOException if createProcess fails for e.g. ffmpeg or youtube-dl.

join :: GuildId -> ChannelId -> Voice (Voice ()) Source #

Join a specific voice channel, given the Guild and Channel ID of the voice channel. Since the Channel ID is globally unique, there is theoretically no need to specify the Guild ID, but it is provided until discord-haskell fully caches the mappings internally.

This function returns a Voice action that, when executed, will leave the joined voice channel. For example:

runVoice $ do
  leave <- join (read "123456789012345") (read "67890123456789012")
  playYouTube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  leave

The above use is not meaningful in practice, since runVoice will perform the appropriate cleanup and leaving as necessary at the end of all actions. However, it may be useful to interleave leave with other Voice actions.

Since the leave function will gracefully do nothing if the voice connection is already severed, it is safe to escape this function from the Voice monad and use it in a different context. That is, the following is allowed and is encouraged if you are building a /leave command of any sort:

-- On /play
runVoice $ do
  leave <- join (read "123456789012345") (read "67890123456789012")
  liftIO $ putMVar futureLeaveFunc leave
  forever $
    playYouTube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"

-- On /leave, from a different thread
leave <- liftIO $ takeMVar futureLeaveFunc
runVoice leave

The above will join a voice channel, play a YouTube video, but immediately quit and leave the channel when the /leave command is received, regardless of the playback status.

updateSpeakingStatus :: Bool -> Voice () Source #

Helper function to update the speaking indicator for the bot. Setting the microphone status to True is required for Discord to transmit the bot's voice to other clients. It is done automatically in all of the play* functions, so there should be no use for this function in practice.

Note: Soundshare and priority are const as False in the payload because I don't see bots needing them. If and when required, add Bool signatures to this function.

updateStatusVoice Source #

Arguments

:: GuildId

Id of Guild

-> Maybe ChannelId

Id of the voice channel client wants to join (Nothing if disconnecting)

-> Bool

Whether the client muted

-> Bool

Whether the client deafened

-> DiscordHandler () 

Send a Gateway Websocket Update Voice State command (Opcode 4). Used to indicate that the client voice status (deaf/mute) as well as the channel they are active on. This is not in the Voice monad because it has to be used after all voice actions end, to quit the voice channels. It also has no benefit, since it would cause extra transformer wrapping/unwrapping.

play :: ConduitT () ByteString (ResourceT DiscordHandler) () -> Voice () Source #

play source plays some sound from the conduit source, provided in the form of 16-bit Little Endian PCM. The use of Conduit allows you to perform arbitrary lazy transformations of audio data, using all the advantages that Conduit brings. As the base monad for the Conduit is ResourceT DiscordHandler, you can access any DiscordHandler effects (through lift) or IO effects (through liftIO) in the conduit as well.

For a more specific interface that is easier to use, see the playPCMFile, playFile, and playYouTube functions.

import Conduit ( sourceFile )

runVoice $ do
  join gid cid
  play $ sourceFile "./audio/example.pcm"

encodeOpusC :: ConduitT ByteString ByteString (ResourceT DiscordHandler) () Source #

encodeOpusC is a conduit that splits the ByteString into chunks of (frame size * no of channels * 16/8) bytes, and encodes each chunk into OPUS format. ByteStrings are made of CChars (Int8)s, but the data is 16-bit so this is why we multiply by two to get the right amount of bytes instead of prematurely cutting off at the half-way point.

playPCMFile Source #

Arguments

:: FilePath

The path to the PCM file to play

-> Voice () 

playPCMFile file plays the sound stored in the file located at file, provided it is in the form of 16-bit Little Endian PCM. playPCMFile is defined as a handy alias for the following:

playPCMFile ≡ play . sourceFile

For a variant of this function that allows arbitrary transformations of the audio data through a conduit component, see playPCMFile'.

To play any other format, it will need to be transcoded using FFmpeg. See playFile for such usage.

playPCMFile' Source #

Arguments

:: FilePath

The path to the PCM file to play

-> ConduitT ByteString ByteString (ResourceT DiscordHandler) ()

Any processing that needs to be done on the audio data

-> Voice () 

playPCMFile' file processor plays the sound stored in the file located at file, provided it is in the form of 16-bit Little Endian PCM. Audio data will be passed through the processor conduit component, allowing arbitrary transformations to audio data before playback. playPCMFile' is defined as the following:

playPCMFile' file processor ≡ play $ sourceFile file .| processor

For a variant of this function with no processing, see playPCMFile.

To play any other format, it will need to be transcoded using FFmpeg. See playFile for such usage.

playFile Source #

Arguments

:: FilePath

The path to the audio file to play

-> Voice () 

playFile file plays the sound stored in the file located at file. It supports any format supported by FFmpeg by transcoding it, which means it can play a wide range of file types. This function expects "ffmpeg" to be available in the system PATH.

For a variant that allows you to specify the executable and/or any arguments, see playFileWith.

For a variant of this function that allows arbitrary transformations of the audio data through a conduit component, see playFile'.

If the file is already known to be in 16-bit little endian PCM, using playPCMFile is much more efficient as it does not go through FFmpeg.

playFile' Source #

Arguments

:: FilePath

The path to the audio file to play

-> ConduitT ByteString ByteString (ResourceT DiscordHandler) ()

Any processing that needs to be done on the audio data

-> Voice () 

playFile' file processor plays the sound stored in the file located at file. It supports any format supported by FFmpeg by transcoding it, which means it can play a wide range of file types. This function expects "ffmpeg" to be available in the system PATH. Audio data will be passed through the processor conduit component, allowing arbitrary transformations to audio data before playback.

For a variant that allows you to specify the executable and/or any arguments, see playFileWith'.

For a variant of this function with no processing, see playFile.

If the file is already known to be in 16-bit little endian PCM, using playPCMFile' is much more efficient as it does not go through FFmpeg.

defaultFFmpegArgs :: FilePath -> [String] Source #

defaultFFmpegArgs is a generator function for the default FFmpeg arguments used when streaming audio into 16-bit little endian PCM on stdout.

This function takes in the input file path as an argument, because FFmpeg arguments are position sensitive in relation to the placement of -i.

It is defined semantically as:

defaultFFmpegArgs FILE ≡ "-i FILE -f s16le -ar 48000 -ac 2 -loglevel warning pipe:1"

playFileWith Source #

Arguments

:: String

The name of the FFmpeg executable

-> (String -> [String])

FFmpeg argument generator function, given the filepath

-> FilePath

The path to the audio file to play

-> Voice () 

playFileWith exe args file plays the sound stored in the file located at file, using the specified FFmpeg executable exe and an argument generator function args (see defaultFFmpegArgs for the default). It supports any format supported by FFmpeg by transcoding it, which means it can play a wide range of file types.

For a variant of this function that uses the "ffmpeg" executable in your PATH automatically, see playFile.

For a variant of this function that allows arbitrary transformations of the audio data through a conduit component, see playFileWith'.

If the file is known to be in 16-bit little endian PCM, using playPCMFile is more efficient as it does not go through FFmpeg.

playFileWith' Source #

Arguments

:: String

The name of the FFmpeg executable

-> (String -> [String])

FFmpeg argument generator function, given the filepath

-> String

The path to the audio file to play

-> ConduitT ByteString ByteString (ResourceT DiscordHandler) ()

Any processing that needs to be done on the audio data

-> Voice () 

playFileWith' exe args file processor plays the sound stored in the file located at file, using the specified FFmpeg executable exe and an argument generator function args (see defaultFFmpegArgs for the default). It supports any format supported by FFmpeg by transcoding it, which means it can play a wide range of file types. Audio data will be passed through the processor conduit component, allowing arbitrary transformations to audio data before playback.

For a variant of this function that uses the "ffmpeg" executable in your PATH automatically, see playFile'.

For a variant of this function with no processing, see playFileWith.

If the file is known to be in 16-bit little endian PCM, using playPCMFile' is more efficient as it does not go through FFmpeg.

playYouTube Source #

Arguments

:: String

Search query (or video URL)

-> Voice () 

playYouTube query plays the first result of searching query on YouTube. If a direct video URL is given, YouTube will always return that as the first result, which means playYouTube also supports playing links. It supports all videos, by automatically transcoding to PCM using FFmpeg. Since it streams the data instead of downloading it first, it can play live videos as well. This function expects "ffmpeg" and "youtube-dl" to be available in the system PATH.

For a variant that allows you to specify the executable and/or any arguments, see playYouTubeWith.

For a variant of this function that allows arbitrary transformations of the audio data through a conduit component, see playYouTube'.

playYouTube' Source #

Arguments

:: String

Search query (or video URL)

-> ConduitT ByteString ByteString (ResourceT DiscordHandler) ()

Any processing that needs to be done on the audio data

-> Voice () 

playYouTube' query processor plays the first result of searching query on YouTube. If a direct video URL is given, YouTube will always return that as the first result, which means playYouTube also supports playing links. It supports all videos, by automatically transcoding to PCM using FFmpeg. Since it streams the data instead of downloading it first, it can play live videos as well. This function expects "ffmpeg" and "youtube-dl" to be available in the system PATH. Audio data will be passed through the processor conduit component, allowing arbitrary transformations to audio data before playback.

For a variant that allows you to specify the executable and/or any arguments, see playYouTubeWith'.

For a variant of this function with no processing, see playYouTube.

playYouTubeWith Source #

Arguments

:: String

The name of the FFmpeg executable

-> (String -> [String])

FFmpeg argument generator function, given the URL

-> String

The name of the youtube-dl executable

-> String

The search query (or video URL)

-> Voice () 

playYouTubeWith fexe fargs yexe query plays the first result of searching query on YouTube, using the specified youtube-dl executable yexe, FFmpeg executable fexe and an argument generator function fargs (see defaultFFmpegArgs for the default). If a direct video URL is given, YouTube will always return that as the first result, which means playYouTube also supports playing links. It supports all videos, by automatically transcoding to PCM using FFmpeg. Since it streams the data instead of downloading it first, it can play live videos as well.

For a variant of this function that uses the "ffmpeg" executable and "youtube-dl" executable in your PATH automatically, see playYouTube.

For a variant of this function that allows arbitrary transformations of the audio data through a conduit component, see playYouTubeWith'.

playYouTubeWith' Source #

Arguments

:: String

The name of the FFmpeg executable

-> (String -> [String])

The arguments to pass to FFmpeg

-> String

The name of the youtube-dl executable

-> String

The search query (or video URL)

-> ConduitT ByteString ByteString (ResourceT DiscordHandler) ()

Any processing that needs to be done on the audio data

-> Voice () 

playYouTubeWith' fexe fargs yexe query processor plays the first result of searching query on YouTube, using the specified youtube-dl executable yexe, FFmpeg executable fexe and an argument generator function fargs (see defaultFFmpegArgs for the default). If a direct video URL is given, YouTube will always return that as the first result, which means playYouTube also supports playing links. It supports all videos, by automatically transcoding to PCM using FFmpeg. Since it streams the data instead of downloading it first, it can play live videos as well. Audio data will be passed through the processor conduit component, allowing arbitrary transformations to audio data before playback.

For a variant of this function that uses the "ffmpeg" executable and "youtube-dl" executable in your PATH automatically, see playYouTube'.

For a variant of this function with no processing, see playYouTubeWith.