Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voicechannel Recording. #34

Merged
merged 10 commits into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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