diff --git a/src/main/java/com/ubivashka/plasmovoice/audio/codecs/ICodecHolder.java b/src/main/java/com/ubivashka/plasmovoice/audio/codecs/ICodecHolder.java index 10ffc74..49f0d1b 100644 --- a/src/main/java/com/ubivashka/plasmovoice/audio/codecs/ICodecHolder.java +++ b/src/main/java/com/ubivashka/plasmovoice/audio/codecs/ICodecHolder.java @@ -27,4 +27,12 @@ public interface ICodecHolder { byte[] encode(byte[] data); byte[] decode(byte[] data); + + void resetEncoder(); + + void resetDecoder(); + + void closeEncoder(); + + void closeDecoder(); } diff --git a/src/main/java/com/ubivashka/plasmovoice/audio/codecs/OpusCodecHolder.java b/src/main/java/com/ubivashka/plasmovoice/audio/codecs/OpusCodecHolder.java index c1b5c9f..e8778b3 100644 --- a/src/main/java/com/ubivashka/plasmovoice/audio/codecs/OpusCodecHolder.java +++ b/src/main/java/com/ubivashka/plasmovoice/audio/codecs/OpusCodecHolder.java @@ -1,53 +1,65 @@ package com.ubivashka.plasmovoice.audio.codecs; -import javax.sound.sampled.AudioFormat; - +import com.ubivashka.plasmovoice.function.MemoizingSupplier; import com.ubivashka.plasmovoice.opus.OpusDecoder; import com.ubivashka.plasmovoice.opus.OpusEncoder; - import de.maxhenkel.opus4j.Opus; +import javax.sound.sampled.AudioFormat; +import java.util.function.Supplier; + public class OpusCodecHolder extends AbstractCodecHolder { - private static final int MTU_SIZE = 1024; - private static final int JOPUS_MODE = Opus.OPUS_APPLICATION_VOIP; - - private OpusEncoder encoder = new OpusEncoder(sampleRate, frameSize, MTU_SIZE, JOPUS_MODE); - private OpusDecoder decoder = new OpusDecoder(sampleRate, frameSize, MTU_SIZE); - - public OpusEncoder getEncoder() { - return encoder; - } - - public void setEncoder(OpusEncoder encoder) { - this.encoder = encoder; - } - - public OpusDecoder getDecoder() { - return decoder; - } - - public void setDecoder(OpusDecoder decoder) { - this.decoder = decoder; - } - - @Override - public byte[] encode(byte[] data) { - return encoder.encode(data); - } - - @Override - public byte[] decode(byte[] data) { - return decoder.decode(data); - } - - @Override - public void setSampleRate(int sampleRate) { - this.sampleRate = sampleRate; - this.audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); - this.frameSize = (sampleRate / 1000) * 2 * 20; - - this.encoder = new OpusEncoder(sampleRate, frameSize, MTU_SIZE, JOPUS_MODE); - this.decoder = new OpusDecoder(sampleRate, frameSize, MTU_SIZE); - } + private static final int MTU_SIZE = 1024; + private static final int JOPUS_MODE = Opus.OPUS_APPLICATION_VOIP; + + private Supplier lazyEncoder = MemoizingSupplier.memoize(() -> new OpusEncoder(sampleRate, frameSize, MTU_SIZE, JOPUS_MODE)); + private Supplier lazyDecoder = MemoizingSupplier.memoize(() -> new OpusDecoder(sampleRate, frameSize, MTU_SIZE)); + + public OpusEncoder getEncoder() { + return lazyEncoder.get(); + } + + public OpusDecoder getDecoder() { + return lazyDecoder.get(); + } + + @Override + public byte[] encode(byte[] data) { + return getEncoder().encode(data); + } + + @Override + public byte[] decode(byte[] data) { + return getDecoder().decode(data); + } + + @Override + public void resetEncoder() { + getEncoder().reset(); + } + + @Override + public void closeEncoder() { + getEncoder().close(); + } + + public void resetDecoder() { + getDecoder().reset(); + } + + @Override + public void closeDecoder() { + getDecoder().close(); + } + + @Override + public void setSampleRate(int sampleRate) { + this.sampleRate = sampleRate; + this.audioFormat = new AudioFormat(sampleRate, 16, 1, true, false); + this.frameSize = (sampleRate / 1000) * 2 * 20; + + lazyEncoder = MemoizingSupplier.memoize(() -> new OpusEncoder(sampleRate, frameSize, MTU_SIZE, JOPUS_MODE)); + lazyDecoder = MemoizingSupplier.memoize(() -> new OpusDecoder(sampleRate, frameSize, MTU_SIZE)); + } } diff --git a/src/main/java/com/ubivashka/plasmovoice/audio/player/ISoundPlayer.java b/src/main/java/com/ubivashka/plasmovoice/audio/player/ISoundPlayer.java index f393af6..65d0cd7 100644 --- a/src/main/java/com/ubivashka/plasmovoice/audio/player/ISoundPlayer.java +++ b/src/main/java/com/ubivashka/plasmovoice/audio/player/ISoundPlayer.java @@ -18,7 +18,7 @@ public interface ISoundPlayer { ISoundPlaySession playSound(ISound sound, IAudioSource audioSource, ISoundController soundController); /** - * @return Возвращает кодек с которым можно сжимать и обратить этот процесс. + * @return Создаёт кодек с которым можно сжимать и обратить этот процесс. */ - ICodecHolder getCodecHolder(); + ICodecHolder createCodecHolder(); } diff --git a/src/main/java/com/ubivashka/plasmovoice/audio/player/PlasmoVoiceSoundPlayer.java b/src/main/java/com/ubivashka/plasmovoice/audio/player/PlasmoVoiceSoundPlayer.java index 64f901f..5577301 100644 --- a/src/main/java/com/ubivashka/plasmovoice/audio/player/PlasmoVoiceSoundPlayer.java +++ b/src/main/java/com/ubivashka/plasmovoice/audio/player/PlasmoVoiceSoundPlayer.java @@ -14,13 +14,11 @@ import su.plo.voice.PlasmoVoice; public class PlasmoVoiceSoundPlayer implements ISoundPlayer { - private final OpusCodecHolder opusCodecHolder = new OpusCodecHolder(); @Override public ISoundPlaySession playSound(ISound sound, IAudioSource audioSource, ISoundController soundController) { if (!(audioSource instanceof IPlayerAudioSource) || !(soundController instanceof PlasmoVoiceSoundController)) return null; - updateCodecHolder(); IPlayerAudioSource playerAudioSource = (IPlayerAudioSource) audioSource; Player player = Bukkit.getPlayer(playerAudioSource.getPlayerUniqueId()); if (player == null) @@ -28,13 +26,11 @@ public ISoundPlaySession playSound(ISound sound, IAudioSource audioSource, ISoun return new PlasmoVoiceSoundPlaySession(sound, playerAudioSource, (PlasmoVoiceSoundController) soundController); } - private void updateCodecHolder() { - opusCodecHolder.setSampleRate(PlasmoVoice.getInstance().getVoiceConfig().getSampleRate()); - } - @Override - public ICodecHolder getCodecHolder() { - return opusCodecHolder; + public ICodecHolder createCodecHolder() { + ICodecHolder codecHolder = new OpusCodecHolder(); + codecHolder.setSampleRate(PlasmoVoice.getInstance().getVoiceConfig().getSampleRate()); + return codecHolder; } } diff --git a/src/main/java/com/ubivashka/plasmovoice/function/MemoizingSupplier.java b/src/main/java/com/ubivashka/plasmovoice/function/MemoizingSupplier.java new file mode 100644 index 0000000..4768429 --- /dev/null +++ b/src/main/java/com/ubivashka/plasmovoice/function/MemoizingSupplier.java @@ -0,0 +1,45 @@ +package com.ubivashka.plasmovoice.function; + +import java.io.Serializable; +import java.util.function.Supplier; + +public final class MemoizingSupplier implements Supplier, Serializable { + + final Supplier delegate; + transient volatile boolean initialized; + // "value" does not need to be volatile; visibility piggy-backs + // on volatile read of "initialized". + transient T value; + + MemoizingSupplier(Supplier delegate) { + this.delegate = delegate; + } + + @Override + public T get() { + // A 2-field variant of Double Checked Locking. + if (!initialized) { + synchronized (this) { + if (!initialized) { + T t = delegate.get(); + value = t; + initialized = true; + return t; + } + } + } + return value; + } + + @Override + public String toString() { + return "Suppliers.memoize(" + delegate + ")"; + } + + private static final long serialVersionUID = 0; + + public static Supplier memoize(Supplier supplier) { + return new MemoizingSupplier<>(supplier); + } + +} \ No newline at end of file diff --git a/src/main/java/com/ubivashka/plasmovoice/opus/OpusEncoder.java b/src/main/java/com/ubivashka/plasmovoice/opus/OpusEncoder.java index 510aa3b..a2d925a 100644 --- a/src/main/java/com/ubivashka/plasmovoice/opus/OpusEncoder.java +++ b/src/main/java/com/ubivashka/plasmovoice/opus/OpusEncoder.java @@ -1,15 +1,14 @@ package com.ubivashka.plasmovoice.opus; +import com.sun.jna.ptr.PointerByReference; +import com.ubivashka.plasmovoice.opus.utils.AudioUtils; +import de.maxhenkel.opus4j.Opus; + import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; -import com.sun.jna.ptr.PointerByReference; -import com.ubivashka.plasmovoice.opus.utils.AudioUtils; - -import de.maxhenkel.opus4j.Opus; - public class OpusEncoder { protected PointerByReference opusEncoder; protected int sampleRate; diff --git a/src/main/java/com/ubivashka/plasmovoice/sound/SoundBuilder.java b/src/main/java/com/ubivashka/plasmovoice/sound/SoundBuilder.java index 221e28f..32fc4f7 100644 --- a/src/main/java/com/ubivashka/plasmovoice/sound/SoundBuilder.java +++ b/src/main/java/com/ubivashka/plasmovoice/sound/SoundBuilder.java @@ -37,7 +37,7 @@ public ISound build() throws UnsupportedAudioFileException, IOException { switch (soundFormat) { case WAV: AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(inputStream); - sound = new AudioStreamSound(audioInputStream, PLUGIN.getPlasmoVoiceSoundPlayer().getCodecHolder(), true); + sound = new AudioStreamSound(audioInputStream, PLUGIN.getPlasmoVoiceSoundPlayer().createCodecHolder(), true); break; case MP3: sound = new MP3Sound(inputStream, PLUGIN.getPlasmoVoiceSoundPlayer()); diff --git a/src/main/java/com/ubivashka/plasmovoice/sound/mp3/MP3Sound.java b/src/main/java/com/ubivashka/plasmovoice/sound/mp3/MP3Sound.java index 3450eff..15f0774 100644 --- a/src/main/java/com/ubivashka/plasmovoice/sound/mp3/MP3Sound.java +++ b/src/main/java/com/ubivashka/plasmovoice/sound/mp3/MP3Sound.java @@ -36,7 +36,7 @@ public MP3Sound(InputStream musicInputStream, ISoundPlayer player) throws IOExce baseFormat.getSampleRate(), false); audioInputStream = new MpegFormatConversionProvider().getAudioInputStream(targetFormat, audioInputStream); - convertedSound = new AudioStreamSound(audioInputStream, player.getCodecHolder(), true); + convertedSound = new AudioStreamSound(audioInputStream, player.createCodecHolder(), true); } @Override diff --git a/src/main/java/com/ubivashka/plasmovoice/sound/pcm/AudioStreamSound.java b/src/main/java/com/ubivashka/plasmovoice/sound/pcm/AudioStreamSound.java index f90d8fd..eefd248 100644 --- a/src/main/java/com/ubivashka/plasmovoice/sound/pcm/AudioStreamSound.java +++ b/src/main/java/com/ubivashka/plasmovoice/sound/pcm/AudioStreamSound.java @@ -24,7 +24,7 @@ public class AudioStreamSound implements ISound { * ICodecHolder */ public AudioStreamSound(AudioInputStream audioInputStream, ISoundPlayer soundPlayer) { - this(audioInputStream, soundPlayer.getCodecHolder(), false); + this(audioInputStream, soundPlayer.createCodecHolder(), false); } /** @@ -33,7 +33,7 @@ public AudioStreamSound(AudioInputStream audioInputStream, ISoundPlayer soundPla * получить из файла или InputStream используйте (Можно * и другим способом): * {@link javax.sound.sampled.AudioSystem} - * @param soundPlayer - Используется для сжатия звука + * @param codecHolder - Используется для сжатия звука * @param convert - Решает конвертировать ли формат звука */ public AudioStreamSound(AudioInputStream audioInputStream, ICodecHolder codecHolder, boolean convert) { @@ -45,6 +45,7 @@ public AudioStreamSound(AudioInputStream audioInputStream, ICodecHolder codecHol try { new AudioInputStreamReader(newAudioInputStream, (data) -> newDataList.add(codecHolder.encode(data))) .read(codecHolder.getFrameSize()); + codecHolder.closeEncoder(); } catch (IOException e) { e.printStackTrace(); }