From 7dda40130b771fcb6965881273cf0d0798e26f23 Mon Sep 17 00:00:00 2001 From: James Ball Date: Thu, 24 Jun 2021 12:02:41 +0100 Subject: [PATCH] Remove requirement for a render lock by making listener queue thread-safe --- .../java/sh/ball/audio/ShapeAudioPlayer.java | 37 +++++++------------ .../sh/ball/audio/engine/AudioEngine.java | 3 +- .../sh/ball/audio/engine/XtAudioEngine.java | 11 +----- 3 files changed, 16 insertions(+), 35 deletions(-) diff --git a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java index 141a936..4142682 100644 --- a/src/main/java/sh/ball/audio/ShapeAudioPlayer.java +++ b/src/main/java/sh/ball/audio/ShapeAudioPlayer.java @@ -4,8 +4,7 @@ import sh.ball.audio.effect.Effect; import java.io.*; import java.util.*; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; +import java.util.concurrent.*; import sh.ball.audio.engine.AudioDevice; import sh.ball.audio.engine.AudioEngine; @@ -14,8 +13,7 @@ import sh.ball.shapes.Vector2; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; -import java.util.concurrent.Callable; -import java.util.concurrent.Semaphore; +import javax.sound.sampled.LineUnavailableException; import java.util.concurrent.locks.ReentrantLock; public class ShapeAudioPlayer implements AudioPlayer> { @@ -33,8 +31,7 @@ public class ShapeAudioPlayer implements AudioPlayer> { private final Callable audioEngineBuilder; private final BlockingQueue> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE); private final Map effects = new HashMap<>(); - private final ReentrantLock renderLock = new ReentrantLock(); - private final List listeners = new ArrayList<>(); + private final List listeners = new CopyOnWriteArrayList<>(); private AudioEngine audioEngine; private ByteArrayOutputStream outputStream; @@ -83,13 +80,13 @@ public class ShapeAudioPlayer implements AudioPlayer> { } private void writeChannels(float leftChannel, float rightChannel) { - int left = (int)(leftChannel * Short.MAX_VALUE); - int right = (int)(rightChannel * Short.MAX_VALUE); + int left = (int) (leftChannel * Short.MAX_VALUE); + int right = (int) (rightChannel * Short.MAX_VALUE); byte b0 = (byte) left; - byte b1 = (byte)(left >> 8); + byte b1 = (byte) (left >> 8); byte b2 = (byte) right; - byte b3 = (byte)(right >> 8); + byte b3 = (byte) (right >> 8); if (recording) { outputStream.write(b0); @@ -155,7 +152,11 @@ public class ShapeAudioPlayer implements AudioPlayer> { throw new IllegalArgumentException("No AudioDevice provided"); } - audioEngine.play(this::generateChannels, renderLock, device); + try { + audioEngine.play(this::generateChannels, device); + } catch (Exception e) { + e.printStackTrace(); + } } @Override @@ -200,19 +201,9 @@ public class ShapeAudioPlayer implements AudioPlayer> { @Override public void read(byte[] buffer) throws InterruptedException { Listener listener = new Listener(buffer); - try { - renderLock.lock(); - listeners.add(listener); - } finally { - renderLock.unlock(); - } + listeners.add(listener); listener.waitUntilFull(); - try { - renderLock.lock(); - listeners.remove(listener); - } finally { - renderLock.unlock(); - } + listeners.remove(listener); } @Override diff --git a/src/main/java/sh/ball/audio/engine/AudioEngine.java b/src/main/java/sh/ball/audio/engine/AudioEngine.java index f947cb9..7cca723 100644 --- a/src/main/java/sh/ball/audio/engine/AudioEngine.java +++ b/src/main/java/sh/ball/audio/engine/AudioEngine.java @@ -4,12 +4,11 @@ import sh.ball.shapes.Vector2; import java.util.List; import java.util.concurrent.Callable; -import java.util.concurrent.locks.ReentrantLock; public interface AudioEngine { boolean isPlaying(); - void play(Callable channelGenerator, ReentrantLock renderLock, AudioDevice device); + void play(Callable channelGenerator, AudioDevice device) throws Exception; void stop(); diff --git a/src/main/java/sh/ball/audio/engine/XtAudioEngine.java b/src/main/java/sh/ball/audio/engine/XtAudioEngine.java index 96dfdd7..c48d8a0 100644 --- a/src/main/java/sh/ball/audio/engine/XtAudioEngine.java +++ b/src/main/java/sh/ball/audio/engine/XtAudioEngine.java @@ -8,7 +8,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.concurrent.locks.ReentrantLock; public class XtAudioEngine implements AudioEngine { @@ -19,7 +18,6 @@ public class XtAudioEngine implements AudioEngine { private AudioDevice device; private boolean playing = false; - private ReentrantLock renderLock; private Callable channelGenerator; public XtAudioEngine() {} @@ -27,9 +25,6 @@ public class XtAudioEngine implements AudioEngine { private int render(XtStream stream, Structs.XtBuffer buffer, Object user) throws Exception { XtSafeBuffer safe = XtSafeBuffer.get(stream); safe.lock(buffer); - if (renderLock != null) { - renderLock.lock(); - } Object output = safe.getOutput(); for (int f = 0; f < buffer.frames; f++) { @@ -37,9 +32,6 @@ public class XtAudioEngine implements AudioEngine { writeChannels(channels, output, f); } safe.unlock(buffer); - if (renderLock != null) { - renderLock.unlock(); - } return 0; } @@ -97,11 +89,10 @@ public class XtAudioEngine implements AudioEngine { } @Override - public void play(Callable channelGenerator, ReentrantLock renderLock, AudioDevice device) { + public void play(Callable channelGenerator, AudioDevice device) { this.playing = true; this.device = device; this.channelGenerator = channelGenerator; - this.renderLock = renderLock; try (XtPlatform platform = XtAudio.init(null, null)) { XtService service = getService(platform);