diff --git a/src/main/java/net/dv8tion/jda/api/audio/hooks/ConnectionListener.java b/src/main/java/net/dv8tion/jda/api/audio/hooks/ConnectionListener.java index 14521e811f..2c67861570 100644 --- a/src/main/java/net/dv8tion/jda/api/audio/hooks/ConnectionListener.java +++ b/src/main/java/net/dv8tion/jda/api/audio/hooks/ConnectionListener.java @@ -16,8 +16,11 @@ package net.dv8tion.jda.api.audio.hooks; +import net.dv8tion.jda.annotations.ForRemoval; +import net.dv8tion.jda.annotations.ReplaceWith; import net.dv8tion.jda.api.audio.SpeakingMode; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.UserSnowflake; import javax.annotation.Nonnull; import java.util.EnumSet; @@ -46,8 +49,6 @@ public interface ConnectionListener */ void onStatusChange(@Nonnull ConnectionStatus status); - // TODO: Deprecate and replace these onUserSpeaking methods. - /** * This method is an easy way to detect if a user is talking. Discord sends us an event when a user starts or stops * talking and it is parallel to the audio socket, so this event could come milliseconds before or after audio begins @@ -69,8 +70,16 @@ public interface ConnectionListener * Never-null {@link net.dv8tion.jda.api.entities.User User} who's talking status has changed. * @param speaking * If true, the user has begun transmitting audio. + * + * @deprecated This method no longer represents the actual speaking state of the user. + * Discord does not send updates when a user starts and stops speaking anymore. + * You can use {@link #onUserSpeakingModeUpdate(UserSnowflake, EnumSet)} to see when a user changes their speaking mode, + * or use an {@link net.dv8tion.jda.api.audio.AudioReceiveHandler AudioReceiveHandler} to check when a user is speaking. */ - void onUserSpeaking(@Nonnull User user, boolean speaking); + @Deprecated + @ForRemoval + @ReplaceWith("onUserSpeakingModeUpdate(User, EnumSet)") + default void onUserSpeaking(@Nonnull User user, boolean speaking) {} /** * This method is an easy way to detect if a user is talking. Discord sends us an event when a user starts or stops @@ -97,7 +106,15 @@ public interface ConnectionListener * * @see java.util.EnumSet EnumSet * @see net.dv8tion.jda.api.audio.SpeakingMode SpeakingMode + * + * @deprecated This method no longer represents the actual speaking state of the user. + * Discord does not send updates when a user starts and stops speaking anymore. + * You can use {@link #onUserSpeakingModeUpdate(UserSnowflake, EnumSet)} to see when a user changes their speaking mode, + * or use an {@link net.dv8tion.jda.api.audio.AudioReceiveHandler AudioReceiveHandler} to check when a user is speaking. */ + @Deprecated + @ForRemoval + @ReplaceWith("onUserSpeakingModeUpdate(User, EnumSet)") default void onUserSpeaking(@Nonnull User user, @Nonnull EnumSet modes) {} @@ -124,6 +141,46 @@ default void onUserSpeaking(@Nonnull User user, @Nonnull EnumSet m * If true, the user has begun transmitting audio. * @param soundshare * If true, the user is using soundshare + * + * @deprecated This method no longer represents the actual speaking state of the user. + * Discord does not send updates when a user starts and stops speaking anymore. + * You can use {@link #onUserSpeakingModeUpdate(UserSnowflake, EnumSet)} to see when a user changes their speaking mode, + * or use an {@link net.dv8tion.jda.api.audio.AudioReceiveHandler AudioReceiveHandler} to check when a user is speaking. */ + @Deprecated + @ForRemoval + @ReplaceWith("onUserSpeakingModeUpdate(User, EnumSet)") default void onUserSpeaking(@Nonnull User user, boolean speaking, boolean soundshare) {} + + /** + * This method is used to listen for users changing their speaking mode. + *

Whenever a user joins a voice channel, this is fired once to define the initial speaking modes. + * + *

To detect when a user is speaking, a {@link net.dv8tion.jda.api.audio.AudioReceiveHandler AudioReceiveHandler} should be used instead. + * + *

Note: This requires the user to be currently in the cache. + * You can use {@link net.dv8tion.jda.api.utils.MemberCachePolicy#VOICE MemberCachePolicy.VOICE} to cache currently connected users. + * Alternatively, use {@link #onUserSpeakingModeUpdate(UserSnowflake, EnumSet)} to avoid cache. + * + * @param user + * The user who changed their speaking mode + * @param modes + * The new speaking modes of the user + */ + default void onUserSpeakingModeUpdate(@Nonnull User user, @Nonnull EnumSet modes) {} + + /** + * This method is used to listen for users changing their speaking mode. + *

Whenever a user joins a voice channel, this is fired once to define the initial speaking modes. + * + *

To detect when a user is speaking, a {@link net.dv8tion.jda.api.audio.AudioReceiveHandler AudioReceiveHandler} should be used instead. + * + *

This method works independently of the user cache. The provided user might not be cached. + * + * @param user + * The user who changed their speaking mode + * @param modes + * The new speaking modes of the user + */ + default void onUserSpeakingModeUpdate(@Nonnull UserSnowflake user, @Nonnull EnumSet modes) {} } diff --git a/src/main/java/net/dv8tion/jda/api/audio/hooks/ListenerProxy.java b/src/main/java/net/dv8tion/jda/api/audio/hooks/ListenerProxy.java index f6c9417783..3872154b94 100644 --- a/src/main/java/net/dv8tion/jda/api/audio/hooks/ListenerProxy.java +++ b/src/main/java/net/dv8tion/jda/api/audio/hooks/ListenerProxy.java @@ -18,6 +18,7 @@ import net.dv8tion.jda.api.audio.SpeakingMode; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.UserSnowflake; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +95,27 @@ public void onUserSpeaking(@Nonnull User user, @Nonnull EnumSet mo } @Override - public void onUserSpeaking(@Nonnull User user, boolean speaking) {} + public void onUserSpeakingModeUpdate(@Nonnull UserSnowflake user, @Nonnull EnumSet modes) + { + if (listener == null) + return; + ConnectionListener listener = this.listener; + try + { + if (listener != null) + { + listener.onUserSpeakingModeUpdate(user, modes); + if (user instanceof User) + listener.onUserSpeakingModeUpdate((User) user, modes); + } + } + catch (Throwable t) + { + log.error("The ConnectionListener encountered and uncaught exception", t); + if (t instanceof Error) + throw (Error) t; + } + } public void setListener(ConnectionListener listener) { diff --git a/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java b/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java index 523a04a289..8365f80a1c 100644 --- a/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java +++ b/src/main/java/net/dv8tion/jda/internal/audio/AudioWebSocket.java @@ -23,6 +23,7 @@ import net.dv8tion.jda.api.audio.hooks.ConnectionStatus; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.UserSnowflake; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel; import net.dv8tion.jda.api.events.ExceptionEvent; import net.dv8tion.jda.api.utils.MiscUtil; @@ -501,15 +502,22 @@ private void handleEvent(DataObject contentAll) final long userId = content.getLong("user_id"); final User user = getUser(userId); + if (user == null) { //more relevant for audio connection LOG.trace("Got an Audio USER_SPEAKING_UPDATE for a non-existent User. JSON: {}", contentAll); - break; + listener.onUserSpeakingModeUpdate(UserSnowflake.fromId(userId), speaking); + } + else + { + //noinspection deprecation + listener.onUserSpeaking(user, speaking); + listener.onUserSpeakingModeUpdate((UserSnowflake) user, speaking); } audioConnection.updateUserSSRC(ssrc, userId); - listener.onUserSpeaking(user, speaking); + break; } case VoiceCode.USER_DISCONNECT: