Nostrum.Voice (Nostrum v0.5.0-rc2) View Source

Interface for playing audio through Discord's voice channels.

Using Discord Voice Channels

To play sound in Discord with Nostrum, you'll need ffmpeg to be installed. If you don't have the executable ffmpeg in the path, the absolute path may be configured through config keys :nostrum, :ffmpeg. If you don't want to use ffmpeg, read on to the next section.

A bot may be connected to at most one voice channel per guild. For this reason, most of the functions in this module take a guild id, and the resulting action will be performed in the given guild's voice channel that the bot is connected to.

The primary Discord gateway responsible for all text based communication relies on one websocket connection per shard, where small bots typically only have one shard. The Discord voice gateways work by establishing a websocket connection per guild/channel. After some handshaking on this connection, audio data can be sent over UDP/RTP. Behind the scenes the voice websocket connections are implemented nearly the same way the main shard websocket connections are, and require no developer intervention.

Voice Without FFmpeg

If you wish to BYOE (Bring Your Own Encoder), there are a few options.

Link to this section Summary

Functions

Returns a specification to start this module under a supervisor.

Low-level. Manually connect to voice websockets gateway.

Gets the id of the voice channel that the bot is connected to.

Leaves the voice channel of the given guild id.

Listen for incoming voice RTP packets.

Pauses the current sound being played in a voice channel.

Plays sound in the voice channel the bot is in.

Checks if the bot is playing sound in a voice channel.

Checks if the connection is up and ready to play audio.

Resumes playing the current paused sound in a voice channel.

Low-level. Send pre-encoded audio packets directly.

Low-level. Set speaking flag in voice channel.

Stops the current sound being played in a voice channel.

Link to this section Functions

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

connect_to_gateway(guild_id)

View Source (since 0.5.0)

Specs

connect_to_gateway(Nostrum.Struct.Guild.id()) :: :ok | {:error, String.t()}

Low-level. Manually connect to voice websockets gateway.

This function should only be called if config option :voice_auto_connect is set to false. By default Nostrum will automatically create a voice gateway when joining a channel.

Link to this function

get_channel_id(guild_id)

View Source

Specs

Gets the id of the voice channel that the bot is connected to.

Parameters

  • guild_id - ID of guild that the resultant channel belongs to.

Returns the channel_id for the channel the bot is connected to, otherwise nil.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.get_channel(123456789)
420691337

iex> Nostrum.Voice.leave_channel(123456789)

iex> Nostrum.Voice.get_channel(123456789)
nil
Link to this function

join_channel(guild_id, channel_id, self_mute \\ false, self_deaf \\ false)

View Source

Specs

Joins or moves the bot to a voice channel.

This function is equivalent to Nostrum.Api.update_voice_state/4.

Specs

leave_channel(Nostrum.Struct.Guild.id()) :: no_return() | :ok

Leaves the voice channel of the given guild id.

This function is equivalent to calling Nostrum.Api.update_voice_state(guild_id, nil).

Link to this function

listen(guild_id, num_packets)

View Source (since 0.5.0)

Specs

listen(Nostrum.Struct.Guild.id(), pos_integer()) ::
  [{binary(), binary()}] | {:error, String.t()}

Listen for incoming voice RTP packets.

Parameters

  • guild_id - ID of guild that the bot is listening to.
  • num_packets - Number of packets to wait for.

Returns a list of 2-element tuples in the form {rtp_header, opus_packet}.

This function will block until the specified number of packets is received.

Specs

pause(Nostrum.Struct.Guild.id()) :: :ok | {:error, String.t()}

Pauses the current sound being played in a voice channel.

The bot must be connected to a voice channel in the guild specified.

Parameters

  • guild_id - ID of guild whose voice channel the sound will be paused in.

Returns {:error, reason} if unable to pause or no sound is playing, else :ok.

This function is similar to stop/1, except that the sound may be resumed after being paused.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "~/files/twelve_hour_loop_of_waterfall_sounds.mp3")

iex> Nostrum.Voice.pause(123456789)
Link to this function

play(guild_id, input, type \\ :url, options \\ [])

View Source

Specs

play(
  Nostrum.Struct.Guild.id(),
  String.t() | binary() | iodata() | Enum.t(),
  :url | :pipe | :ytdl | :stream | :raw | :raw_s,
  keyword()
) :: :ok | {:error, String.t()}

Plays sound in the voice channel the bot is in.

The bot must be connected to a voice channel in the guild specified.

Parameters

  • guild_id - ID of guild whose voice channel the sound will be played in.
  • input - Audio to be played. Type of input determined by type parameter.
  • type - Type of input (defaults to :url).
    • :url Input will be any url that ffmpeg can read.
    • :pipe Input will be data that is piped to stdin of ffmpeg.
    • :ytdl Input will be url for youtube-dl, which gets automatically piped to ffmpeg.
    • :stream Input will be livestream url for streamlink, which gets automatically piped to ffmpeg.
    • :raw Input will be an enumarable of raw opus frames. This bypasses ffmpeg and all options.
    • :raw_s Same as :raw but input must be stateful, i.e. calling Enum.take/2 on input is not idempotent.
  • options - See options section below.

Returns {:error, reason} if unable to play or a sound is playing, else :ok.

Options

  • :start_pos (string) - The start position of the audio to be played. Defaults to beginning.
  • :duration (string) - The duration to of the audio to be played . Defaults to entire duration.
  • :realtime (boolean) - Make ffmpeg process the input in realtime instead of as fast as possible. Defaults to true.
  • :volume (number) - The output volume of the audio. Default volume is 1.0.
  • :filter (string) - Filter(s) to be applied to the audio. No filters applied by default.

The values of :start_pos and :duration can be any time duration that ffmpeg can read. The :filter can be used multiple times in a single call (see examples). The values of :filter can be any audio filters that ffmpeg can read. Filters will be applied in order and can be as complex as you want. The world is your oyster!

Note that using the :volume option is shortcut for the "volume" filter, and will be added to the end of the filter chain, acting as a master volume. Volume values between 0.0 and 1.0 act as standard oparating range where 0 is off and 1 is max. Values greater than 1.0 will add saturation and distortion to the audio. Negative values act the same as their position but reverse the polarity of the waveform.

Having all the ffmpeg audio filters available is extremely powerful so it may be worth learning some of them for your use cases. If you use any filters to increase the playback speed of your audio, it's recommended to set the :realtime option to false because realtime processing is relative to the original playback speed.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "~/music/FavoriteSong.mp3", :url)

iex> Nostrum.Voice.play(123456789, "~/music/NotFavoriteButStillGoodSong.mp3", :url, volume: 0.5)

iex> Nostrum.Voice.play(123456789, "~/music/ThisWillBeHeavilyDistorted.mp3", :url, volume: 1000)
iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> raw_data = File.read!("~/music/sound_effect.wav")

iex> Nostrum.Voice.play(123456789, raw_data, :pipe)
iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "https://www.youtube.com/watch?v=b4RJ-QGOtw4", :ytdl,
...>   realtime: true, start_pos: "0:17", duration: "30")

iex> Nostrum.Voice.play(123456789, "https://www.youtube.com/watch?v=0ngcL_5ekXo", :ytdl,
...>   filter: "lowpass=f=1200", filter: "highpass=f=300", filter: "asetrate=44100*0.5")
iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "https://www.twitch.tv/pestily", :stream)

iex> Nostrum.Voice.play(123456789, "https://youtu.be/LN4r-K8ZP5Q", :stream)

Specs

playing?(Nostrum.Struct.Guild.id()) :: boolean()

Checks if the bot is playing sound in a voice channel.

Parameters

  • guild_id - ID of guild to check if audio being played.

Returns true if the bot is currently being played in a voice channel, otherwise false.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "https://a-real-site.biz/RickRoll.m4a")

iex> Nostrum.Voice.playing?(123456789)
true

iex> Nostrum.Voice.pause(123456789)

iex> Nostrum.Voice.playing?(123456789)
false

Specs

Checks if the connection is up and ready to play audio.

Parameters

  • guild_id - ID of guild to check if voice connection is up.

Returns true if the bot is connected to a voice channel, otherwise false.

This function does not check if audio is already playing. For that, use playing?/1.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.ready?(123456789)
true

iex> Nostrum.Voice.leave_channel(123456789)

iex> Nostrum.Voice.ready?(123456789)
false

Specs

resume(Nostrum.Struct.Guild.id()) :: :ok | {:error, String.t()}

Resumes playing the current paused sound in a voice channel.

The bot must be connected to a voice channel in the guild specified.

Parameters

  • guild_id - ID of guild whose voice channel the sound will be resumed in.

Returns {:error, reason} if unable to resume or no sound has been paused, otherwise returns :ok.

This function is used to resume a sound that had previously been paused.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "~/stuff/Toto - Africa (Bass Boosted)")

iex> Nostrum.Voice.pause(123456789)

iex> Nostrum.Voice.resume(123456789)
Link to this function

send_frames(guild_id, frames)

View Source (since 0.5.0)

Specs

send_frames(Nostrum.Struct.Guild.id(), [binary()]) :: :ok | {:error, String.t()}

Low-level. Send pre-encoded audio packets directly.

Speaking should be set to true via Nostrum.Voice.set_is_speaking/2 before sending frames.

Opus frames will be encrypted and prefixed with the appropriate RTP header and sent immediately. The length of frames depends on how often you wish to send a sequence of frames. A single frame contains 20ms of audio. Sending more than 50 frames (1 second of audio) in a single function call may result in inconsistent playback rates.

Nostrum.Voice.playing?/1 will not return accurate values when using send_frames/2 instead of Nostrum.Voice.play/4

Link to this function

set_is_speaking(guild_id, speaking)

View Source (since 0.5.0)

Specs

set_is_speaking(Nostrum.Struct.Guild.id(), boolean()) :: :ok

Low-level. Set speaking flag in voice channel.

This function does not need to be called unless you are sending audio frames directly using Nostrum.Voice.send_frames/2.

Specs

stop(Nostrum.Struct.Guild.id()) :: :ok | {:error, String.t()}

Stops the current sound being played in a voice channel.

The bot must be connected to a voice channel in the guild specified.

Parameters

  • guild_id - ID of guild whose voice channel the sound will be stopped in.

Returns {:error, reason} if unable to stop or no sound is playing, else :ok.

If a sound has finished playing, this function does not need to be called to start playing another sound.

Examples

iex> Nostrum.Voice.join_channel(123456789, 420691337)

iex> Nostrum.Voice.play(123456789, "http://brandthill.com/files/weird_dubstep_noises.mp3")

iex> Nostrum.Voice.stop(123456789)