From fcc963734b5f812ab25a9e7f4b0a7ad782c01dc4 Mon Sep 17 00:00:00 2001 From: Apehum Date: Mon, 8 Jun 2026 20:47:34 +0800 Subject: [PATCH 1/6] use @InjectPlasmoVoice annotation (cherry picked from commit 86d199363edc6d67673d2c37ebf57ce420604ecf) --- CPM-PV-Compat/gradle.properties | 4 ++-- CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/CPM-PV-Compat/gradle.properties b/CPM-PV-Compat/gradle.properties index 7616952a..684cb2f3 100644 --- a/CPM-PV-Compat/gradle.properties +++ b/CPM-PV-Compat/gradle.properties @@ -1,7 +1,7 @@ org.gradle.jvmargs=-Xmx4G org.gradle.daemon=false -mod_version=1.1.1 +mod_version=1.1.2 # CPM versions cpm_api_version=0.6.26 @@ -18,4 +18,4 @@ maven_name=cpmpvc neo_version=21.1.131 neo_minecraft_version=1.21 -neo_java_version=21 \ No newline at end of file +neo_java_version=21 diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java index ff6d3562..4cff03a5 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java @@ -3,13 +3,12 @@ import java.util.Optional; import java.util.UUID; -import com.google.inject.Inject; - import com.tom.cpm.shared.MinecraftClientAccess; import su.plo.voice.api.addon.AddonInitializer; import su.plo.voice.api.addon.AddonLoaderScope; import su.plo.voice.api.addon.ClientAddonsLoader; +import su.plo.voice.api.addon.InjectPlasmoVoice; import su.plo.voice.api.addon.annotation.Addon; import su.plo.voice.api.client.PlasmoVoiceClient; import su.plo.voice.api.client.connection.ServerConnection; @@ -19,14 +18,14 @@ import su.plo.voice.client.audio.source.ClientPlayerSource; import su.plo.voice.proto.data.player.VoicePlayerInfo; -@Addon(id = CPMPVC.MOD_ID, scope = AddonLoaderScope.CLIENT, version = "2.1.1", authors = "tom5454") +@Addon(id = CPMPVC.MOD_ID, scope = AddonLoaderScope.CLIENT, version = "2.1.2", authors = "tom5454") public class CPMAddon implements AddonInitializer { public static final CPMAddon INSTANCE = new CPMAddon(); private CPMAddon() { } - @Inject + @InjectPlasmoVoice private PlasmoVoiceClient voiceClient; @Override From bf7b8edccb5b47a29437eb6fbe3da8dfdbd47904 Mon Sep 17 00:00:00 2001 From: Apehum Date: Mon, 8 Jun 2026 20:55:20 +0800 Subject: [PATCH 2/6] check if actually speaking in AudioCaptureProcessedEvent (cherry picked from commit cc6ced0f5f9ba35c8e61e246683b671da1658360) --- .../src/shared/java/com/tom/cpmpvc/CPMAddon.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java index 4cff03a5..84ff7e95 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java @@ -11,6 +11,7 @@ import su.plo.voice.api.addon.InjectPlasmoVoice; import su.plo.voice.api.addon.annotation.Addon; import su.plo.voice.api.client.PlasmoVoiceClient; +import su.plo.voice.api.client.audio.capture.ClientActivation; import su.plo.voice.api.client.connection.ServerConnection; import su.plo.voice.api.client.event.audio.capture.AudioCaptureProcessedEvent; import su.plo.voice.api.client.event.audio.source.AudioSourceWriteEvent; @@ -39,7 +40,13 @@ public static void init() { @EventSubscribe public void onCaptureProcessed(AudioCaptureProcessedEvent event) { - CPMPVC.handle(event.getProcessed().getMono()); + // AudioCaptureProcessedEvent triggers even when audio is not actually sent to the server + // so we have to check if any activation is active right now to see if player is speaking + boolean isSpeaking = voiceClient.getActivationManager() + .getActivations() + .stream().anyMatch(ClientActivation::isActive); + + CPMPVC.handle(isSpeaking ? event.getProcessed().getMono() : null); } @EventSubscribe From 4bd8204ae4d70b16eb65943547eec68df8c13343 Mon Sep 17 00:00:00 2001 From: Apehum Date: Mon, 8 Jun 2026 21:06:07 +0800 Subject: [PATCH 3/6] check for client mute in #isMuted (cherry picked from commit 8d2a4e65d36bd480ed55f58c7ba708ac44e5b977) --- .../src/shared/java/com/tom/cpmpvc/CPMAddon.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java index 84ff7e95..57e3e703 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMAddon.java @@ -62,11 +62,21 @@ public boolean isMuted(UUID player) { if (!connection.isPresent()) return false; Optional playerInfo = connection.get().getPlayerById(player); - if (!playerInfo.isPresent())return false; - if (playerInfo.get().isMuted() || playerInfo.get().isMicrophoneMuted())return true; + if (!playerInfo.isPresent()) return false; + + boolean isMutedOnServer = playerInfo.get().isMuted(); + boolean inMutedOnClient = voiceClient.getConfig() + .getVoice() + .getVolumes() + .getMute("source_" + player) + .value(); + + if (isMutedOnServer || inMutedOnClient) return true; + if (MinecraftClientAccess.get().getCurrentClientPlayer().getUUID().equals(player)) { return voiceClient.getConfig().getVoice().getMicrophoneDisabled().value(); } + return false; } } From 1aeafb0fc2c3be3a5f73b9598fcf536d8752d578 Mon Sep 17 00:00:00 2001 From: Apehum Date: Tue, 9 Jun 2026 14:53:12 +0800 Subject: [PATCH 4/6] use pv's AudioUtil for audio level calculations (cherry picked from commit fd7964b5cbdc594c1ad0867541de9b5401cee0b2) --- .../shared/java/com/tom/cpmpvc/CPMPVC.java | 55 +------------------ 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java index 863eaa6b..dd282a3c 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java @@ -12,6 +12,7 @@ import com.tom.cpm.api.IClientAPI.MessageSender; import com.tom.cpm.shared.MinecraftClientAccess; +import su.plo.voice.api.util.AudioUtil; public class CPMPVC { public static final String MOD_ID = "cpmpvc"; @@ -36,62 +37,10 @@ public static void handle(UUID uuid, short[] data) { } private static float calcVoiceLevel(short[] data) { - return (float) dbToPerc(getHighestAudioLevel(data)); + return (float) AudioUtil.audioLevelToDoubleRange(AudioUtil.calculateHighestAudioLevel(data)); } public static boolean isMuted(UUID uuid) { return CPMAddon.INSTANCE.isMuted(uuid); } - - /** - * Calculates the audio level of a signal with specific samples. - * - * @param samples the samples of the signal to calculate the audio level of - * @param offset the offset in samples in which the samples start - * @param length the length in bytes of the signal in samples starting at offset - * @return the audio level of the specified signal in db - */ - private static double calculateAudioLevel(short[] samples, int offset, int length) { - double rms = 0D; // root mean square (RMS) amplitude - - for (int i = offset; i < length; i++) { - double sample = (double) samples[i] / (double) Short.MAX_VALUE; - rms += sample * sample; - } - - int sampleCount = length / 2; - - rms = (sampleCount == 0) ? 0 : Math.sqrt(rms / sampleCount); - - double db; - - if (rms > 0D) { - db = Math.min(Math.max(20D * Math.log10(rms), -127D), 0D); - } else { - db = -127D; - } - - return db; - } - - /** - * Calculates the highest audio level in packs of 100 - * - * @param samples the audio samples - * @return the audio level in db - */ - private static double getHighestAudioLevel(short[] samples) { - double highest = -127D; - for (int i = 0; i < samples.length; i += 100) { - double level = calculateAudioLevel(samples, i, Math.min(i + 100, samples.length)); - if (level > highest) { - highest = level; - } - } - return highest; - } - - private static double dbToPerc(double db) { - return (db + 127D) / 127D; - } } From 1dc4caff0c974d200b65a4513e3b45f69da08489 Mon Sep 17 00:00:00 2001 From: Apehum Date: Tue, 9 Jun 2026 14:58:05 +0800 Subject: [PATCH 5/6] remove unused mutedSender (cherry picked from commit a7e9f9dd1cd78a6b2df82c76910d6f9a183d141a) --- CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java index dd282a3c..4d19430a 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java @@ -10,7 +10,6 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.tom.cpm.api.IClientAPI.MessageSender; import com.tom.cpm.shared.MinecraftClientAccess; import su.plo.voice.api.util.AudioUtil; @@ -18,7 +17,6 @@ public class CPMPVC { public static final String MOD_ID = "cpmpvc"; public static final Logger LOGGER = LogManager.getLogger("CPM-PV Compat"); private static final LoadingCache voiceLevelsCache = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.SECONDS).build(CacheLoader.from(() -> 0f)); - public static MessageSender mutedSender; public static float get(UUID uuid) { try { From 9b53c2fdf15d0952919a5a258b8f5a8b14168c10 Mon Sep 17 00:00:00 2001 From: Apehum Date: Thu, 18 Jun 2026 14:54:39 +0800 Subject: [PATCH 6/6] Revert "use pv's AudioUtil for audio level calculations" This reverts commit 1aeafb0fc2c3be3a5f73b9598fcf536d8752d578. --- .../shared/java/com/tom/cpmpvc/CPMPVC.java | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java index 4d19430a..2cd10c86 100644 --- a/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java +++ b/CPM-PV-Compat/src/shared/java/com/tom/cpmpvc/CPMPVC.java @@ -11,7 +11,6 @@ import com.google.common.cache.LoadingCache; import com.tom.cpm.shared.MinecraftClientAccess; -import su.plo.voice.api.util.AudioUtil; public class CPMPVC { public static final String MOD_ID = "cpmpvc"; @@ -35,10 +34,62 @@ public static void handle(UUID uuid, short[] data) { } private static float calcVoiceLevel(short[] data) { - return (float) AudioUtil.audioLevelToDoubleRange(AudioUtil.calculateHighestAudioLevel(data)); + return (float) dbToPerc(getHighestAudioLevel(data)); } public static boolean isMuted(UUID uuid) { return CPMAddon.INSTANCE.isMuted(uuid); } + + /** + * Calculates the audio level of a signal with specific samples. + * + * @param samples the samples of the signal to calculate the audio level of + * @param offset the offset in samples in which the samples start + * @param length the length in bytes of the signal in samples starting at offset + * @return the audio level of the specified signal in db + */ + private static double calculateAudioLevel(short[] samples, int offset, int length) { + double rms = 0D; // root mean square (RMS) amplitude + + for (int i = offset; i < length; i++) { + double sample = (double) samples[i] / (double) Short.MAX_VALUE; + rms += sample * sample; + } + + int sampleCount = length / 2; + + rms = (sampleCount == 0) ? 0 : Math.sqrt(rms / sampleCount); + + double db; + + if (rms > 0D) { + db = Math.min(Math.max(20D * Math.log10(rms), -127D), 0D); + } else { + db = -127D; + } + + return db; + } + + /** + * Calculates the highest audio level in packs of 100 + * + * @param samples the audio samples + * @return the audio level in db + */ + private static double getHighestAudioLevel(short[] samples) { + double highest = -127D; + for (int i = 0; i < samples.length; i += 100) { + double level = calculateAudioLevel(samples, i, Math.min(i + 100, samples.length)); + if (level > highest) { + highest = level; + } + } + return highest; + } + + private static double dbToPerc(double db) { + return (db + 127D) / 127D; + } }