Browse Source

docs: add explanation to RunMode.Async in voice docs

tags/2.0
Christopher F 6 years ago
parent
commit
c7e7f7e51a
1 changed files with 39 additions and 30 deletions
  1. +39
    -30
      docs/guides/voice/sending-voice.md

+ 39
- 30
docs/guides/voice/sending-voice.md View File

@@ -11,16 +11,16 @@ Information is not guaranteed to be accurate.


## Installing ## Installing


Audio requires two native libraries, `libsodium` and `opus`.
Both of these libraries must be placed in the runtime directory of your
bot. (When developing on .NET Framework, this would be `bin/debug`,
when developing on .NET Core, this is where you execute `dotnet run`
Audio requires two native libraries, `libsodium` and `opus`.
Both of these libraries must be placed in the runtime directory of your
bot. (When developing on .NET Framework, this would be `bin/debug`,
when developing on .NET Core, this is where you execute `dotnet run`
from; typically the same directory as your csproj). from; typically the same directory as your csproj).


For Windows Users, precompiled binaries are available for your
For Windows Users, precompiled binaries are available for your
convienence [here](https://discord.foxbot.me/binaries/). convienence [here](https://discord.foxbot.me/binaries/).


For Linux Users, you will need to compile [Sodium] and [Opus] from
For Linux Users, you will need to compile [Sodium] and [Opus] from
source, or install them from your package manager. source, or install them from your package manager.


[Sodium]: https://download.libsodium.org/libsodium/releases/ [Sodium]: https://download.libsodium.org/libsodium/releases/
@@ -28,7 +28,7 @@ source, or install them from your package manager.


## Joining a Channel ## Joining a Channel


Joining a channel is the first step to sending audio, and will return
Joining a channel is the first step to sending audio, and will return
an [IAudioClient] to send data with. an [IAudioClient] to send data with.


To join a channel, simply await [ConnectAsync] on any instance of an To join a channel, simply await [ConnectAsync] on any instance of an
@@ -36,67 +36,76 @@ To join a channel, simply await [ConnectAsync] on any instance of an


[!code-csharp[Joining a Channel](samples/joining_audio.cs)] [!code-csharp[Joining a Channel](samples/joining_audio.cs)]


The client will sustain a connection to this channel until it is
>[!WARNING]
>Commands which mutate voice states, such as those where you join/leave
>an audio channel, or send audio, should use [RunMode.Async]. RunMode.Async
>is necessary to prevent a feedback loop which will deadlock clients
>in their default configuration. If you know that you're running your
>commands in a different task than the gateway task, RunMode.Async is
>not required.

The client will sustain a connection to this channel until it is
kicked, disconnected from Discord, or told to disconnect. kicked, disconnected from Discord, or told to disconnect.


It should be noted that voice connections are created on a per-guild
basis; only one audio connection may be open by the bot in a single
guild. To switch channels within a guild, invoke [ConnectAsync] on
It should be noted that voice connections are created on a per-guild
basis; only one audio connection may be open by the bot in a single
guild. To switch channels within a guild, invoke [ConnectAsync] on
another voice channel in the guild. another voice channel in the guild.


[IAudioClient]: xref:Discord.Audio.IAudioClient [IAudioClient]: xref:Discord.Audio.IAudioClient
[ConnectAsync]: xref:Discord.IAudioChannel.ConnectAsync* [ConnectAsync]: xref:Discord.IAudioChannel.ConnectAsync*
[RunMode.Async]: xref:Discord.Commands.RunMode


## Transmitting Audio ## Transmitting Audio


### With FFmpeg ### With FFmpeg


[FFmpeg] is an open source, highly versatile AV-muxing tool. This is
[FFmpeg] is an open source, highly versatile AV-muxing tool. This is
the recommended method of transmitting audio. the recommended method of transmitting audio.


Before you begin, you will need to have a version of FFmpeg downloaded
and placed somewhere in your PATH (or alongside the bot, in the same
location as libsodium and opus). Windows binaries are available on
Before you begin, you will need to have a version of FFmpeg downloaded
and placed somewhere in your PATH (or alongside the bot, in the same
location as libsodium and opus). Windows binaries are available on
[FFmpeg's download page]. [FFmpeg's download page].


[FFmpeg]: https://ffmpeg.org/ [FFmpeg]: https://ffmpeg.org/
[FFmpeg's download page]: https://ffmpeg.org/download.html [FFmpeg's download page]: https://ffmpeg.org/download.html


First, you will need to create a Process that starts FFmpeg. An
example of how to do this is included below, though it is important
First, you will need to create a Process that starts FFmpeg. An
example of how to do this is included below, though it is important
that you return PCM at 48000hz. that you return PCM at 48000hz.


>[!NOTE] >[!NOTE]
>As of the time of this writing, Discord.Audio struggles significantly
>with processing audio that is already opus-encoded; you will need to
>As of the time of this writing, Discord.Audio struggles significantly
>with processing audio that is already opus-encoded; you will need to
>use the PCM write streams. >use the PCM write streams.


[!code-csharp[Creating FFmpeg](samples/audio_create_ffmpeg.cs)] [!code-csharp[Creating FFmpeg](samples/audio_create_ffmpeg.cs)]


Next, to transmit audio from FFmpeg to Discord, you will need to
pull an [AudioOutStream] from your [IAudioClient]. Since we're using
Next, to transmit audio from FFmpeg to Discord, you will need to
pull an [AudioOutStream] from your [IAudioClient]. Since we're using
PCM audio, use [IAudioClient.CreatePCMStream]. PCM audio, use [IAudioClient.CreatePCMStream].


The sample rate argument doesn't particularly matter, so long as it is
a valid rate (120, 240, 480, 960, 1920, or 2880). For the sake of
The sample rate argument doesn't particularly matter, so long as it is
a valid rate (120, 240, 480, 960, 1920, or 2880). For the sake of
simplicity, I recommend using 1920. simplicity, I recommend using 1920.


Channels should be left at `2`, unless you specified a different value
Channels should be left at `2`, unless you specified a different value
for `-ac 2` when creating FFmpeg. for `-ac 2` when creating FFmpeg.


[AudioOutStream]: xref:Discord.Audio.AudioOutStream [AudioOutStream]: xref:Discord.Audio.AudioOutStream
[IAudioClient.CreatePCMStream]: xref:Discord.Audio.IAudioClient#Discord_Audio_IAudioClient_CreateDirectPCMStream_Discord_Audio_AudioApplication_System_Nullable_System_Int32__System_Int32_ [IAudioClient.CreatePCMStream]: xref:Discord.Audio.IAudioClient#Discord_Audio_IAudioClient_CreateDirectPCMStream_Discord_Audio_AudioApplication_System_Nullable_System_Int32__System_Int32_


Finally, audio will need to be piped from FFmpeg's stdout into your
AudioOutStream. This step can be as complex as you'd like it to be, but
for the majority of cases, you can just use [Stream.CopyToAsync], as
Finally, audio will need to be piped from FFmpeg's stdout into your
AudioOutStream. This step can be as complex as you'd like it to be, but
for the majority of cases, you can just use [Stream.CopyToAsync], as
shown below. shown below.


[Stream.CopyToAsync]: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx [Stream.CopyToAsync]: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx


If you are implementing a queue for sending songs, it's likely that
you will want to wait for audio to stop playing before continuing on
to the next song. You can await `AudioOutStream.FlushAsync` to wait for
If you are implementing a queue for sending songs, it's likely that
you will want to wait for audio to stop playing before continuing on
to the next song. You can await `AudioOutStream.FlushAsync` to wait for
the audio client's internal buffer to clear out. the audio client's internal buffer to clear out.


[!code-csharp[Sending Audio](samples/audio_ffmpeg.cs)] [!code-csharp[Sending Audio](samples/audio_ffmpeg.cs)]

Loading…
Cancel
Save