Skip to content

Commit

Permalink
Merge pull request #34 from Ree6-Applications/feature/voice-recording
Browse files Browse the repository at this point in the history
Voicechannel Recording.
  • Loading branch information
OfficialError authored Jul 12, 2022
2 parents 7872cb1 + 51a84a7 commit 2556cba
Show file tree
Hide file tree
Showing 63 changed files with 598 additions and 324 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<groupId>com.github.DV8FromTheWorld</groupId>
<artifactId>JDA</artifactId>
<version>5.0.0-alpha.13</version>
<version>07e8166fc5</version>
</dependency>
<dependency>
<groupId>me.carleslc.Simple-YAML</groupId>
Expand Down
121 changes: 121 additions & 0 deletions src/main/java/de/presti/ree6/audio/AudioPlayerReceiveHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package de.presti.ree6.audio;

import de.presti.ree6.utils.data.AudioUtil;
import net.dv8tion.jda.api.audio.AudioReceiveHandler;
import net.dv8tion.jda.api.audio.CombinedAudio;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.VoiceChannel;
import org.jetbrains.annotations.NotNull;

import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/*
All methods in this class are called by JDA threads when resources are available/ready for processing.
The receiver will be provided with the latest 20ms of PCM stereo audio
Note you can receive even while setting yourself to deafened
*/
public class AudioPlayerReceiveHandler implements AudioReceiveHandler {

/**
* Queue of audio to be sent afterwards.
*/
private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>();

/**
* Boolean used to indicated that handler finished his Job.
*/
private boolean finished = false;

/**
* The voice channel this handler is currently handling.
*/
private final VoiceChannel voiceChannel;

/**
* Constructor.
*
* @param voiceChannel The voice channel this handler should handle.
*/
public AudioPlayerReceiveHandler(VoiceChannel voiceChannel) {
this.voiceChannel = voiceChannel;
}

/**
* @see AudioReceiveHandler#canReceiveCombined()
*/
@Override // combine multiple user audio-streams into a single one
public boolean canReceiveCombined() {
/* one entry = 20ms of audio, which means 20 * 100 = 2000ms = 2s of audio,
* but since we want to allow up to 5 minute of audio we have to do
* 20 * 100 * 150 = 300.000ms = 5 minutes of audio.
* And since 100 entries are 2s we would need 15000 entries for 5 minutes of audio.
*/
return queue.size() < 15000;
}

/**
* @see AudioReceiveHandler#canReceiveUser()
*/
@Override
public boolean includeUserInCombinedAudio(@NotNull User user) {
return !user.isBot();
}

/**
* @see AudioReceiveHandler#handleCombinedAudio(CombinedAudio)
*/
@Override
public void handleCombinedAudio(CombinedAudio combinedAudio) {
if (finished) {
return;
}

if (combinedAudio.getUsers().isEmpty()) {
if (voiceChannel.getMembers().size() == 1) {
endReceiving();
}
return;
}

if (voiceChannel.getMembers().size() == 1) {
endReceiving();
return;
}

byte[] data = combinedAudio.getAudioData(1.0f);
queue.add(data);

if (!canReceiveCombined()) {
endReceiving();
}
}

/**
* Method called when the recording should stop.
*/
public void endReceiving() {
if (finished) {
return;
}

finished = true;

try {
int queueSize = queue.stream().mapToInt(data -> data.length).sum();
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[queueSize]);
for (byte[] data : queue) {
byteBuffer.put(data);
}

voiceChannel.sendMessage("Here is your audio!").addFile(AudioUtil.convert(byteBuffer), new SimpleDateFormat("dd.MM.yyyy HH/mm").format(System.currentTimeMillis()) + "-" + voiceChannel.getId() + ".wav").queue();
} catch (Exception ex) {
voiceChannel.sendMessage("Something went wrong while converting your audio!\nReason: " + ex.getMessage()).queue();
}

voiceChannel.getGuild().getAudioManager().closeAudioConnection();
queue.clear();
}
}
40 changes: 20 additions & 20 deletions src/main/java/de/presti/ree6/audio/music/MusicWorker.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import net.dv8tion.jda.api.entities.AudioChannel;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.managers.AudioManager;

Expand Down Expand Up @@ -77,10 +77,10 @@ public synchronized GuildMusicManager getGuildAudioPlayer(Guild guild) {
* @param trackUrl the Track URL.
* @param interactionHook a InteractionHook if it was an SlashCommand.
*/
public void loadAndPlaySilence(final TextChannel channel, final AudioChannel audioChannel, final String trackUrl, InteractionHook interactionHook) {
GuildMusicManager musicManager = getGuildAudioPlayer(channel.getGuild());
public void loadAndPlaySilence(final MessageChannelUnion channel, final AudioChannel audioChannel, final String trackUrl, InteractionHook interactionHook) {
GuildMusicManager musicManager = getGuildAudioPlayer(channel.asGuildMessageChannel().getGuild());

musicManager.scheduler.textChannel = channel;
musicManager.scheduler.channel = channel;

playerManager.loadItemOrdered(musicManager, trackUrl, new AudioLoadResultHandler() {
/**
Expand Down Expand Up @@ -121,12 +121,12 @@ public void playlistLoaded(AudioPlaylist playlist) {
@Override
public void noMatches() {
Main.getInstance().getCommandManager().sendMessage(new EmbedBuilder()
.setAuthor(channel.getGuild().getJDA().getSelfUser().getName(), Data.WEBSITE, channel.getGuild().getJDA().getSelfUser().getAvatarUrl())
.setAuthor(channel.asGuildMessageChannel().getGuild().getJDA().getSelfUser().getName(), Data.WEBSITE, channel.asGuildMessageChannel().getGuild().getJDA().getSelfUser().getAvatarUrl())
.setTitle("Music Player!")
.setThumbnail(channel.getGuild().getJDA().getSelfUser().getAvatarUrl())
.setThumbnail(channel.asGuildMessageChannel().getGuild().getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("A Song with the URL ``" + FormatUtil.filter(trackUrl) + "`` couldn't be found!")
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);
}

/**
Expand All @@ -140,7 +140,7 @@ public void loadFailed(FriendlyException exception) {
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("Error while playing: " + exception.getMessage())
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);
}
});
}
Expand All @@ -153,10 +153,10 @@ public void loadFailed(FriendlyException exception) {
* @param trackUrl the Track URL.
* @param interactionHook a InteractionHook if it was an SlashCommand.
*/
public void loadAndPlay(final TextChannel channel, final AudioChannel audioChannel, final String trackUrl, InteractionHook interactionHook) {
GuildMusicManager musicManager = getGuildAudioPlayer(channel.getGuild());
public void loadAndPlay(final MessageChannelUnion channel, final AudioChannel audioChannel, final String trackUrl, InteractionHook interactionHook) {
GuildMusicManager musicManager = getGuildAudioPlayer(channel.asGuildMessageChannel().getGuild());

musicManager.scheduler.textChannel = channel;
musicManager.scheduler.channel = channel;

playerManager.loadItemOrdered(musicManager, trackUrl, new AudioLoadResultHandler() {

Expand All @@ -172,7 +172,7 @@ public void trackLoaded(AudioTrack track) {
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("The Song ``" + FormatUtil.filter(track.getInfo().title) + "`` has been added to the Queue!")
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);

play(audioChannel, musicManager, track);
}
Expand All @@ -196,7 +196,7 @@ public void playlistLoaded(AudioPlaylist playlist) {
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("The Song ``" + FormatUtil.filter(firstTrack.getInfo().title) + "`` has been added to the Queue! (The first Song of the Playlist: " + FormatUtil.filter(playlist.getName()) + ")")
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);

play(audioChannel, musicManager, firstTrack);

Expand All @@ -220,7 +220,7 @@ public void noMatches() {
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("A Song with the URL ``" + FormatUtil.filter(trackUrl) + "`` couldn't be found!")
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);
}

/**
Expand All @@ -234,7 +234,7 @@ public void loadFailed(FriendlyException exception) {
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("Error while playing: " + exception.getMessage())
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);
}
});
}
Expand All @@ -257,15 +257,15 @@ public void play(AudioChannel audioChannel, GuildMusicManager musicManager, Audi
* @param channel the TextChannel, used to inform the user about the skip.
* @param interactionHook the Interaction-Hook, used to replace the channel if it is a SlashCommand.
*/
public void skipTrack(TextChannel channel, InteractionHook interactionHook) {
public void skipTrack(MessageChannelUnion channel, InteractionHook interactionHook) {
Main.getInstance().getCommandManager().sendMessage(new EmbedBuilder().setAuthor(channel.getJDA().getSelfUser().getName(), Data.WEBSITE, channel.getJDA().getSelfUser().getAvatarUrl())
.setTitle("Music Player!")
.setThumbnail(channel.getJDA().getSelfUser().getAvatarUrl())
.setColor(Color.GREEN)
.setDescription("Skipping to the next Song!")
.setFooter(channel.getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.getGuild().getIconUrl()), 5, channel, interactionHook);
.setFooter(channel.asGuildMessageChannel().getGuild().getName() + " - " + Data.ADVERTISEMENT, channel.asGuildMessageChannel().getGuild().getIconUrl()), 5, channel, interactionHook);

getGuildAudioPlayer(channel.getGuild()).scheduler.nextTrack(channel);
getGuildAudioPlayer(channel.asGuildMessageChannel().getGuild()).scheduler.nextTrack(channel);
}

/**
Expand Down Expand Up @@ -325,12 +325,12 @@ public boolean isConnectedMember(Member member) {

public boolean checkInteractPermission(CommandEvent commandEvent) {
if (commandEvent.getMember().getVoiceState() == null || !commandEvent.getMember().getVoiceState().inAudioChannel()) {
Main.getInstance().getCommandManager().sendMessage("Please join a Channel!", commandEvent.getTextChannel(), commandEvent.getInteractionHook());
Main.getInstance().getCommandManager().sendMessage("Please join a Channel!", commandEvent.getChannel(), commandEvent.getInteractionHook());
return false;
}

if (commandEvent.getGuild().getSelfMember().getVoiceState() != null && commandEvent.getGuild().getSelfMember().getVoiceState().inAudioChannel() && commandEvent.getGuild().getSelfMember().getVoiceState().getChannel() != null && commandEvent.getMember().getVoiceState().getChannel() != null && !commandEvent.getGuild().getSelfMember().getVoiceState().getChannel().getId().equalsIgnoreCase(commandEvent.getMember().getVoiceState().getChannel().getId())) {
Main.getInstance().getCommandManager().sendMessage("You have to be in the same Channel as me!", commandEvent.getTextChannel(), commandEvent.getInteractionHook());
Main.getInstance().getCommandManager().sendMessage("You have to be in the same Channel as me!", commandEvent.getChannel(), commandEvent.getInteractionHook());
return false;
}

Expand Down
Loading

0 comments on commit 2556cba

Please sign in to comment.