Examples
For simplicity, all examples are using official mappings.
Groups
Creating a group
VoicechatServerApi api = ...;
Group group = api.groupBuilder()
.setPersistent(true) // Doesn't remove the group once all players left
.setName("My Persistent Group") // The name of the group
.setPassword("SuperSecretPassword") // The password of the group
.setType(Group.Type.ISOLATED) // The type of the group (NORMAL, OPEN, ISOLATED)
.build();
If the group is set to be persistent, the group will be created once the .build()
method is called. If the group is not persistent, the group will be created once the first player is added.
Adding a player to a group
VoicechatServerApi api = ...;
Group group = ...;
Player player = ...;
VoicechatConnection connection = api.getConnectionOf(player.getUUID());
if (connection == null) {
return; // Player does not exist
}
if (connection.getGroup() != null) {
return; // Player is already in a group
}
connection.setGroup(group); // Add player to the group
Audio Channels
Creating a static audio channel
VoicechatServerApi api = ...;
ServerLevel level = ...;
ServerPlayer player = ...;
Vec3 pos = ...;
String category = ...; // The category needs to be registered - See "Registering a volume category"
UUID channelID = UUID.randomUUID();
VoicechatConnection playerConnection = api.getConnectionOf(player.getUUID());
StaticAudioChannel channel = api.createStaticAudioChannel(channelID, api.fromServerLevel(level), playerConnection);
if (channel == null) {
return;
}
channel.setCategory(category); // The category of the audio channel
This will create a static audio channel that can be heard by the player that was provided in the .createStaticAudioChannel(...)
method. Static audio channel audio is the same as the audio in groups.
Creating a locational audio channel
VoicechatServerApi api = ...;
ServerLevel level = ...;
Vec3 pos = ...;
String category = ...; // The category needs to be registered - See "Registering a volume category"
UUID channelID = UUID.randomUUID();
LocationalAudioChannel channel = api.createLocationalAudioChannel(channelID, api.fromServerLevel(level), api.createPosition(pos.x, pos.y, pos.z));
if (channel == null) {
return;
}
channel.setCategory(category); // The category of the audio channel
channel.setDistance(100); // The distance in which the audio channel can be heard
This will create a locational audio channel that can be heard by all players in the range that was defined by .setDistance(distance)
.
Creating an entity audio channel
VoicechatServerApi api = ...;
ServerLevel level = ...;
Entity entity = ...;
String category = ...; // The category needs to be registered - See "Registering a volume category"
UUID channelID = UUID.randomUUID();
EntityAudioChannel channel = api.createEntityAudioChannel(channelID, api.fromEntity(entity));
if (channel == null) {
return;
}
channel.setCategory(category); // The category of the audio channel
channel.setDistance(100); // The distance in which the audio channel can be heard
This will create an entity audio channel that can be heard by all players in the range that was defined by .setDistance(distance)
. The source of the audio channel will be the entity that was provided in the .createEntityAudioChannel(...)
method.
Playing audio to audio channels
VoicechatServerApi api = ...;
LocationalAudioChannel channel = ...; // Can also be a StaticAudioChannel or EntityAudioChannel
short[] audio = ...; // The audio samples in 48kHz 16-bit PCM format
AudioPlayer player = api.createAudioPlayer(channel, api.createEncoder(), audio);
player.startPlaying();
...
player.stopPlaying(); // Stop playing the audio
player.isPlaying(); // Returns true if the audio is currently playing
player.isStopped(); // Returns true if the audio is finished playing or was stopped
player.setOnStopped(() -> {
// This will be called once the audio is finished playing or was stopped
});
This will play the audio to the audio channel in a separate thread. This thread will automatically send the audio packets and will respect the audio pace.
Volume Categories
Registering a volume category
public class Plugin implements VoicechatPlugin {
public static String MUSIC_DISC_CATEGORY = "music_discs"; // This ID must be unique. If a category with the same ID already exists, the category will be replaced
...
@Override
public void registerEvents(EventRegistration registration) {
registration.registerEvent(VoicechatServerStartedEvent.class, this::onServerStarted);
}
private void onServerStarted(VoicechatServerStartedEvent event) {
VoicechatServerApi api = event.getVoicechat();
VolumeCategory musicDiscs = api.volumeCategoryBuilder()
.setId(MUSIC_DISC_CATEGORY)
.setName("Music discs")
.setDescription("The volume of all custom music discs")
.setIcon(getIcon("category_music_discs.png"))
.build();
api.registerVolumeCategory(musicDiscs);
}
@Nullable
private int[][] getIcon(String path) {
try {
Enumeration<URL> resources = Plugin.class.getClassLoader().getResources(path);
while (resources.hasMoreElements()) {
BufferedImage bufferedImage = ImageIO.read(resources.nextElement().openStream());
if (bufferedImage.getWidth() != 16) {
continue;
}
if (bufferedImage.getHeight() != 16) {
continue;
}
int[][] image = new int[16][16];
for (int x = 0; x < bufferedImage.getWidth(); x++) {
for (int y = 0; y < bufferedImage.getHeight(); y++) {
image[x][y] = bufferedImage.getRGB(x, y);
}
}
return image;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
...
}
Setting the category in an audio channel
VoicechatServerApi api = ...;
ServerLevel level = ...;
Vec3 pos = ...;
UUID channelID = UUID.randomUUID();
LocationalAudioChannel channel = api.createLocationalAudioChannel(channelID, api.fromServerLevel(level), api.createPosition(pos.x, pos.y, pos.z));
if (channel == null) {
return;
}
channel.setCategory(MUSIC_DISC_CATEGORY); // The category of the audio channel (Registered in the previous code snippet)
channel.setDistance(100); // The distance in which the audio channel can be heard
Audio Senders
Audio senders act as a player that is sending audio to the server. This only works for players that don't actually have the mod installed. Only one audio sender can be registered per player. The registration of the audio sender will fail if the player already has an audio sender registered or the player is using the voice chat mod.
Registering an audio sender and sending audio
VoicechatServerApi api = ...;
VoicechatConnection connection = ...; // The connection of the player that should act as the sender of the audio
AudioSender sender = api.createAudioSender(connection);
if (!api.registerAudioSender(sender)) {
// The audio sender could not be registered
return;
}
sender.whispering(true); // Acts as the player would be whispering
if (!sender.canSend()) {
// The audio sender can not send audio
// This either means the player has the voice chat mod installed or the player already has an audio sender registered
return;
}
while (...) {
byte[] opusEncodedAudioData = ...; // The opus encoded audio samples
if (!sender.send(opusEncodedAudioData)) {
break; // The audio sender can not send audio
}
// Wait for the next audio packet to be sent
// You need to time the audio packets yourself
// If you send audio packets too fast, some packets may be discarded by the client
}
sender.reset(); // Resets the audio sender, indicating to the client that the end of a continuous audio stream was reached
...
api.unregisterAudioSender(sender); // Unregisters the audio sender. If if its not unregistered, no other plugins can register an audio sender for this player