summaryrefslogtreecommitdiff
path: root/DiscoBot/Audio
diff options
context:
space:
mode:
Diffstat (limited to 'DiscoBot/Audio')
-rw-r--r--DiscoBot/Audio/AudioModule.cs72
-rw-r--r--DiscoBot/Audio/AudioService.cs101
2 files changed, 173 insertions, 0 deletions
diff --git a/DiscoBot/Audio/AudioModule.cs b/DiscoBot/Audio/AudioModule.cs
new file mode 100644
index 0000000..0c3814f
--- /dev/null
+++ b/DiscoBot/Audio/AudioModule.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+
+using DiscoBot;
+using DiscoBot.Audio;
+using DiscoBot.Auxiliary;
+using DiscoBot.Commands;
+
+using Discord;
+using Discord.Commands;
+
+public class AudioModule : ModuleBase
+{
+ // Scroll down further for the AudioService.
+ // Like, way down
+ private readonly AudioService _service;
+
+ // Remember to add an instance of the AudioService
+ // to your IServiceCollection when you initialize your bot
+ public AudioModule(AudioService service)
+ {
+ _service = service;
+ Dsa.Service = service;
+ }
+
+ // You *MUST* mark these commands with 'RunMode.Async'
+ // otherwise the bot will not respond until the Task times out.
+ [Command("_join", RunMode = RunMode.Async)]
+ public async Task JoinCmd()
+ {
+ await _service.JoinAudio(Context.Guild, (Context.User as IVoiceState).VoiceChannel);
+ }
+
+ // Remember to add preconditions to your commands,
+ // this is merely the minimal amount necessary.
+ // Adding more commands of your own is also encouraged.
+ [Command("_leave", RunMode = RunMode.Async)]
+ public async Task LeaveCmd()
+ {
+ await _service.LeaveAudio(Context.Guild);
+ }
+
+ [Command("_play", RunMode = RunMode.Async)]
+ public async Task PlayCmd([Remainder] string song)
+ {
+ if (Dsa.GeneralContext == null)
+ {
+ Dsa.GeneralContext = this.Context;
+ }
+
+ var sounds = Enum.GetValues(typeof(Sound));
+ var soundList = new List<Sound>();
+ foreach (var sound in sounds)
+ {
+ soundList.Add((Sound)sound);
+ }
+
+ var sc = new SpellCorrect();
+
+ var tSound = soundList.OrderBy(x => sc.Compare(song, x.ToString())).First();
+
+ if (sc.Compare(song, tSound.ToString()) > SpellCorrect.ErrorThreshold)
+ {
+ await _service.SendAudioAsync(Context.Guild, Context.Channel, song);
+ }
+
+ await SoundEffects.Play(tSound);
+ }
+} \ No newline at end of file
diff --git a/DiscoBot/Audio/AudioService.cs b/DiscoBot/Audio/AudioService.cs
new file mode 100644
index 0000000..25beed0
--- /dev/null
+++ b/DiscoBot/Audio/AudioService.cs
@@ -0,0 +1,101 @@
+namespace DiscoBot.Audio
+{
+ using System.Collections.Concurrent;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Threading.Tasks;
+
+ using Discord;
+ using Discord.Audio;
+
+ public class AudioService
+ {
+ private readonly ConcurrentDictionary<ulong, IAudioClient> connectedChannels = new ConcurrentDictionary<ulong, IAudioClient>();
+
+ public async Task JoinAudio(IGuild guild, IVoiceChannel target)
+ {
+ IAudioClient client;
+ if (this.connectedChannels.TryGetValue(guild.Id, out client))
+ {
+ return;
+ }
+
+ if (target.Guild.Id != guild.Id)
+ {
+ return;
+ }
+
+ var audioClient = await target.ConnectAsync();
+
+ if (this.connectedChannels.TryAdd(guild.Id, audioClient))
+ {
+ // If you add a method to log happenings from this service,
+ // you can uncomment these commented lines to make use of that.
+ //await Log(LogSeverity.Info, $"Connected to voice on {guild.Name}.");
+ }
+ }
+
+ public async Task LeaveAudio(IGuild guild)
+ {
+ IAudioClient client;
+ if (this.connectedChannels.TryRemove(guild.Id, out client))
+ {
+ await client.StopAsync();
+ //await Log(LogSeverity.Info, $"Disconnected from voice on {guild.Name}.");
+ }
+ }
+
+ public async Task SendAudioAsync(IGuild guild, IMessageChannel channel, string path)
+ {
+ // Your task: Get a full path to the file if the value of 'path' is only a filename.
+ if (!File.Exists(path) && false)
+ {
+ await channel.SendMessageAsync("File does not exist.");
+ return;
+ }
+ IAudioClient client;
+ if (this.connectedChannels.TryGetValue(guild.Id, out client))
+ {
+ //await Log(LogSeverity.Debug, $"Starting playback of {path} in {guild.Name}");
+ using (var ffmpeg = this.CreateStream(path))
+ using (var stream = client.CreatePCMStream(AudioApplication.Music))
+ {
+ try { await ffmpeg.StandardOutput.BaseStream.CopyToAsync(stream); }
+ finally { await stream.FlushAsync(); }
+ }
+ }
+ }
+
+ public async Task SendAudioAsync(string path, int Volume)
+ {
+ // Your task: Get a full path to the file if the value of 'path' is only a filename.
+ if (!File.Exists(path) && false)
+ {
+ //await channel.SendMessageAsync("File does not exist.");
+ return;
+ }
+
+ if (this.connectedChannels.TryGetValue(Dsa.GeneralContext.Guild.Id, out var client))
+ {
+ //await Log(LogSeverity.Debug, $"Starting playback of {path} in {guild.Name}");
+ using (var ffmpeg = this.CreateStream(path))
+ using (var stream = client.CreatePCMStream(AudioApplication.Voice))
+ {
+ try { await ffmpeg.StandardOutput.BaseStream.CopyToAsync(stream); }
+ finally { await stream.FlushAsync(); }
+ }
+ }
+ }
+
+ private Process CreateStream(string path)
+ {
+ return Process.Start(new ProcessStartInfo
+ {
+ FileName = "ffmpeg.exe",
+ Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1",
+ UseShellExecute = false,
+ RedirectStandardOutput = true
+ });
+ }
+ }
+}