About¶
Pycord offers multiple ways to play audio streams in a voice channel keeping it as simple and easy as possible, so making any kind of Discord bot is easy for all audiences. This guide provides simple and easy examples of using the multiple ways the library allows you to play audio.
For users that want extra examples, you can find some in Pycord's GitHub repository.
Starting out¶
Pycord natively provides a discord.AudioSource
object. This object defines the structure audio sources must follow in order to be accepted by
the library. For more information on this structure, check the respective documentation.
You usually do not need to manually create subclasses of this object as the library also provides you with the most common audio source types.
PCMAudio¶
PCMAudio is one of Pycord's built-in AudioSource implementations designed to read raw, uncompressed 16-bit, 48 kHz, stereo PCM bytes
directly from an existing byte stream or file. This essentially means that common audio formats
such as mp3, wav, or ogg are not valid, as they are not PCM streams (check FFmpegPCMAudio).
You should only use PCMAudio in specialized or advanced scenarios where you have raw PCM bytes
(such as live audio synthesis or reading from pre-recorded .pcm data) without needing external
tools.
import io
import discord
bot = discord.Bot()
@bot.command()
async def play(ctx: discord.ApplicationContext) -> None:
if not ctx.voice_client:
await ctx.author.voice.channel.connect()
with open("raw_audio.pcm", "rb") as f:
# we use io.BytesIO as a container for the bytes we are reading
pcm_data = io.BytesIO(f.read())
source = discord.PCMAudio(pcm_data)
ctx.voice_client.play(source)
await ctx.respond("Playing PCM audio.")
FFmpegPCMAudio¶
Unlike PCMAudio, FFmpegPCMAudio allows you to pass different audio file formats and automatically
decode them to PCM. This is done by using the ffmpeg (or avconv) executables to convert these audio
streams into manipulable PCM data in a dedicated sub-process.
This intermediate PCM step is slightly more CPU-intensive, as it has to encode the raw audio again into Opus in order to be transmitted to Discord. However, having access to the raw PCM is necessary if you want to manipulate or modify the audio.
import discord
bot = discord.Bot()
@bot.command()
async def play(ctx: discord.ApplicationContext) -> None:
if not ctx.voice_client:
await ctx.author.voice.channel.connect()
# unlike PCMAudio, you do not need to manually open and read
# the file, the library will do it for you.
# FFmpegPCMAudio takes a path to a valid audio file as its first parameter.
# This means that both relative and absolute paths are allowed
source = discord.FFmpegPCMAudio("audio_file.mp3")
ctx.voice_client.play(source)
await ctx.respond("Playing FFmpeg PCM audio.")
PCMVolumeTransformer¶
PCMVolumeTransformer is an audio source that simplifies the volume changing process in PCM sources
(such as PCMAudio or FFmpegPCMAudio) by doing it for you.
This also allows you to dynamically change the volume during playback by just setting a new value for the
volume property.
import discord
bot = discord.Bot()
@bot.command()
async def play(ctx: discord.ApplicationContext, volume: float = 1.0) -> None:
if not ctx.voice_client:
await ctx.author.voice.channel.connect()
# this can be any non-opus source (such as discord.PCMAudio or discord.FFmpegPCMAudio)
original_source = ...
source = discord.PCMVolumeTransformer(original_source, volume=volume)
ctx.voice_client.play(source)
await ctx.respond("Playing volume-transformed PCM audio.")
@bot.command()
async def volume(ctx: discord.ApplicationContext, *, volume: float) -> None:
if not ctx.voice_client or not ctx.voice_client.source:
await ctx.respond("Connect to a voice channel and play something first!")
return
ctx.voice_client.source.volume = volume
await ctx.respond(f"Changed the audio volume to {volume}")
FFmpegOpusAudio¶
This is similar to FFmpegPCMAudio, but, as the name suggests, this does not produce manipulable PCM
streams and directly encodes audio streams to Opus.
This is the most efficient and recommended way to play local media files or web streams directly into a voice channel only when no extra processing (such as changing volume) is required.
FFmpegOpusAudio also uses ffmpeg (or avconv) to encode common audio formats to Opus, which is the
native audio format Discord requires for voice transmission.
Unlike other sources, this one is typically initialized via the FFmpegOpusAudio.from_probe
classmethod.
This analyzes the audio to obtain its codec and bitrate, so it uses the fastest and
most efficient way to encode it to Opus. This is done by using ffprobe (or avprobe).
source = await discord.FFmpegOpusAudio.from_probe("audio.webm")
voice_client.play(source)
FFmpegOpusAudio.from_probe also allows you to pass a custom method, used to determine the codec and
bitrate of the audio source. This can be a string defining whether to use the native probe
(ffprobe / avprobe), or fallback, which falls back to using ffmpeg / avconv. The latter
may be used by Windows users when none of ffprobe or avprobe is installed.
This can also take custom functions which take two parameters, the source and the executable, and
should return a tuple of (codec, bitrate).
import discord
bot = discord.Bot()
@bot.command()
async def play(ctx: discord.ApplicationContext) -> None:
if not ctx.voice_client:
await ctx.author.voice.channel.connect()
source = await discord.FFmpegOpusAudio.from_probe("audio.wav")
ctx.voice_client.play(source)
await ctx.respond("Playing FFmpeg Opus audio.")
And... congratulations! You now know how to implement audio sources for voice channel playback into your bot! Some audio sources may look more complex than others, but all of them keep an easy and simple design so you can make complex bots and get even the most advanced of ideas down.
Related Topics