Created
October 29, 2020 02:59
-
-
Save quanticc/f3ffa8f859624643faaad72490d48d03 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file is part of Discord4J. | |
* | |
* Discord4J is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU Lesser General Public License as published by | |
* the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* Discord4J is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public License | |
* along with Discord4J. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
package discord4j.core; | |
import com.sedmelluq.discord.lavaplayer.format.StandardAudioDataFormats; | |
import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; | |
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; | |
import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; | |
import com.sedmelluq.discord.lavaplayer.player.DefaultAudioPlayerManager; | |
import com.sedmelluq.discord.lavaplayer.source.AudioSourceManagers; | |
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; | |
import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; | |
import com.sedmelluq.discord.lavaplayer.track.AudioTrack; | |
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame; | |
import com.sedmelluq.discord.lavaplayer.track.playback.NonAllocatingAudioFrameBuffer; | |
import discord4j.core.event.domain.message.MessageCreateEvent; | |
import discord4j.core.object.VoiceState; | |
import discord4j.core.object.entity.Member; | |
import discord4j.voice.AudioProvider; | |
import discord4j.voice.AudioReceiver; | |
import discord4j.voice.VoiceConnection; | |
import io.netty.buffer.ByteBufUtil; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import reactor.core.publisher.Mono; | |
import reactor.util.retry.Retry; | |
import java.nio.ByteBuffer; | |
import java.time.Duration; | |
import java.util.Arrays; | |
public class ExampleVoice { | |
private static final Logger log = LoggerFactory.getLogger(ExampleVoice.class); | |
public static void main(String[] args) { | |
GatewayDiscordClient client = DiscordClient.create(System.getenv("token")) | |
.login() | |
.block(); | |
AudioPlayerManager playerManager = new DefaultAudioPlayerManager(); | |
playerManager.getConfiguration().setFrameBufferFactory(NonAllocatingAudioFrameBuffer::new); | |
AudioSourceManagers.registerRemoteSources(playerManager); | |
AudioPlayer player = playerManager.createPlayer(); | |
AudioProvider provider = new LavaplayerAudioProvider(player); | |
AudioReceiver receiver = new AudioReceiver() { | |
@Override | |
public void receive(char sequence, int timestamp, int ssrc, byte[] audio) { | |
log.info("seq={} ts={} ssrc={} audio={}", sequence, timestamp, ssrc, ByteBufUtil.hexDump(audio)); | |
} | |
}; | |
Mono<Void> join = client.on(MessageCreateEvent.class) | |
.filter(e -> e.getMessage().getContent().equals("!join")) | |
.doOnNext(e -> log.info("Received voice join request")) | |
.flatMap(e -> Mono.justOrEmpty(e.getMember()) | |
.flatMap(Member::getVoiceState) | |
.flatMap(VoiceState::getChannel) | |
.flatMap(channel -> channel.join(spec -> spec.setProvider(provider).setReceiver(receiver))) | |
.retryWhen(Retry.backoff(2, Duration.ofSeconds(2))) | |
.doFinally(s -> log.info("Finalized join request after {}", s)) | |
.onErrorResume(t -> { | |
log.error("Failed to join voice channel", t); | |
return Mono.empty(); | |
})) | |
.then(); | |
Mono<Void> leave = client.on(MessageCreateEvent.class) | |
.filter(e -> e.getMessage().getContent().equals("!leave")) | |
.doOnNext(e -> log.info("Received voice leave request")) | |
.flatMap(e -> Mono.justOrEmpty(e.getMember()) | |
.flatMap(Member::getVoiceState) | |
.flatMap(vs -> client.getVoiceConnectionRegistry() | |
.getVoiceConnection(vs.getGuildId()) | |
.doOnSuccess(vc -> { | |
if (vc == null) { | |
log.info("No voice connection to leave!"); | |
} | |
})) | |
.flatMap(VoiceConnection::disconnect)) | |
.then(); | |
Mono<Void> play = client.on(MessageCreateEvent.class) | |
.filter(e -> e.getMessage().getContent().startsWith("!play ")) | |
.flatMap(e -> Mono.justOrEmpty(e.getMessage().getContent()) | |
.map(content -> Arrays.asList(content.split(" "))) | |
.doOnNext(command -> playerManager.loadItem(command.get(1), | |
new MyAudioLoadResultHandler(player)))) | |
.then(); | |
Mono<Void> stop = client.on(MessageCreateEvent.class) | |
.filter(e -> e.getMessage().getContent().equals("!stop")) | |
.doOnNext(e -> player.stopTrack()) | |
.then(); | |
Mono<Void> exit = client.on(MessageCreateEvent.class) | |
.map(event -> event.getMessage().getContent()) | |
.filter(content -> content.equals("!exit")) | |
.flatMap(presence -> client.logout()) | |
.then(); | |
Mono.when(join, leave, play, stop, exit).block(); | |
} | |
private static class LavaplayerAudioProvider extends AudioProvider { | |
private final AudioPlayer player; | |
private final MutableAudioFrame frame = new MutableAudioFrame(); | |
private LavaplayerAudioProvider(AudioPlayer player) { | |
super(ByteBuffer.allocate(StandardAudioDataFormats.DISCORD_OPUS.maximumChunkSize())); | |
this.player = player; | |
this.frame.setBuffer(getBuffer()); | |
} | |
@Override | |
public boolean provide() { | |
boolean didProvide = player.provide(frame); | |
if (didProvide) { | |
getBuffer().flip(); | |
} | |
return didProvide; | |
} | |
} | |
private static class MyAudioLoadResultHandler implements AudioLoadResultHandler { | |
private final AudioPlayer player; | |
private MyAudioLoadResultHandler(AudioPlayer player) { | |
this.player = player; | |
} | |
@Override | |
public void trackLoaded(AudioTrack track) { | |
player.playTrack(track); | |
} | |
@Override | |
public void playlistLoaded(AudioPlaylist playlist) { | |
} | |
@Override | |
public void noMatches() { | |
} | |
@Override | |
public void loadFailed(FriendlyException exception) { | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment