Remove requirement for a render lock by making listener queue thread-safe

pull/35/head
James Ball 2021-06-24 12:02:41 +01:00
rodzic 42c018c422
commit 7dda40130b
3 zmienionych plików z 16 dodań i 35 usunięć

Wyświetl plik

@ -4,8 +4,7 @@ import sh.ball.audio.effect.Effect;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.*;
import java.util.concurrent.BlockingQueue;
import sh.ball.audio.engine.AudioDevice; import sh.ball.audio.engine.AudioDevice;
import sh.ball.audio.engine.AudioEngine; import sh.ball.audio.engine.AudioEngine;
@ -14,8 +13,7 @@ import sh.ball.shapes.Vector2;
import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioInputStream;
import java.util.concurrent.Callable; import javax.sound.sampled.LineUnavailableException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> { public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
@ -33,8 +31,7 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
private final Callable<AudioEngine> audioEngineBuilder; private final Callable<AudioEngine> audioEngineBuilder;
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE); private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
private final Map<Object, Effect> effects = new HashMap<>(); private final Map<Object, Effect> effects = new HashMap<>();
private final ReentrantLock renderLock = new ReentrantLock(); private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private final List<Listener> listeners = new ArrayList<>();
private AudioEngine audioEngine; private AudioEngine audioEngine;
private ByteArrayOutputStream outputStream; private ByteArrayOutputStream outputStream;
@ -83,13 +80,13 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
} }
private void writeChannels(float leftChannel, float rightChannel) { private void writeChannels(float leftChannel, float rightChannel) {
int left = (int)(leftChannel * Short.MAX_VALUE); int left = (int) (leftChannel * Short.MAX_VALUE);
int right = (int)(rightChannel * Short.MAX_VALUE); int right = (int) (rightChannel * Short.MAX_VALUE);
byte b0 = (byte) left; byte b0 = (byte) left;
byte b1 = (byte)(left >> 8); byte b1 = (byte) (left >> 8);
byte b2 = (byte) right; byte b2 = (byte) right;
byte b3 = (byte)(right >> 8); byte b3 = (byte) (right >> 8);
if (recording) { if (recording) {
outputStream.write(b0); outputStream.write(b0);
@ -155,7 +152,11 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
throw new IllegalArgumentException("No AudioDevice provided"); throw new IllegalArgumentException("No AudioDevice provided");
} }
audioEngine.play(this::generateChannels, renderLock, device); try {
audioEngine.play(this::generateChannels, device);
} catch (Exception e) {
e.printStackTrace();
}
} }
@Override @Override
@ -200,19 +201,9 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
@Override @Override
public void read(byte[] buffer) throws InterruptedException { public void read(byte[] buffer) throws InterruptedException {
Listener listener = new Listener(buffer); Listener listener = new Listener(buffer);
try { listeners.add(listener);
renderLock.lock();
listeners.add(listener);
} finally {
renderLock.unlock();
}
listener.waitUntilFull(); listener.waitUntilFull();
try { listeners.remove(listener);
renderLock.lock();
listeners.remove(listener);
} finally {
renderLock.unlock();
}
} }
@Override @Override

Wyświetl plik

@ -4,12 +4,11 @@ import sh.ball.shapes.Vector2;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.locks.ReentrantLock;
public interface AudioEngine { public interface AudioEngine {
boolean isPlaying(); boolean isPlaying();
void play(Callable<Vector2> channelGenerator, ReentrantLock renderLock, AudioDevice device); void play(Callable<Vector2> channelGenerator, AudioDevice device) throws Exception;
void stop(); void stop();

Wyświetl plik

@ -8,7 +8,6 @@ import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.locks.ReentrantLock;
public class XtAudioEngine implements AudioEngine { public class XtAudioEngine implements AudioEngine {
@ -19,7 +18,6 @@ public class XtAudioEngine implements AudioEngine {
private AudioDevice device; private AudioDevice device;
private boolean playing = false; private boolean playing = false;
private ReentrantLock renderLock;
private Callable<Vector2> channelGenerator; private Callable<Vector2> channelGenerator;
public XtAudioEngine() {} public XtAudioEngine() {}
@ -27,9 +25,6 @@ public class XtAudioEngine implements AudioEngine {
private int render(XtStream stream, Structs.XtBuffer buffer, Object user) throws Exception { private int render(XtStream stream, Structs.XtBuffer buffer, Object user) throws Exception {
XtSafeBuffer safe = XtSafeBuffer.get(stream); XtSafeBuffer safe = XtSafeBuffer.get(stream);
safe.lock(buffer); safe.lock(buffer);
if (renderLock != null) {
renderLock.lock();
}
Object output = safe.getOutput(); Object output = safe.getOutput();
for (int f = 0; f < buffer.frames; f++) { for (int f = 0; f < buffer.frames; f++) {
@ -37,9 +32,6 @@ public class XtAudioEngine implements AudioEngine {
writeChannels(channels, output, f); writeChannels(channels, output, f);
} }
safe.unlock(buffer); safe.unlock(buffer);
if (renderLock != null) {
renderLock.unlock();
}
return 0; return 0;
} }
@ -97,11 +89,10 @@ public class XtAudioEngine implements AudioEngine {
} }
@Override @Override
public void play(Callable<Vector2> channelGenerator, ReentrantLock renderLock, AudioDevice device) { public void play(Callable<Vector2> channelGenerator, AudioDevice device) {
this.playing = true; this.playing = true;
this.device = device; this.device = device;
this.channelGenerator = channelGenerator; this.channelGenerator = channelGenerator;
this.renderLock = renderLock;
try (XtPlatform platform = XtAudio.init(null, null)) { try (XtPlatform platform = XtAudio.init(null, null)) {
XtService service = getService(platform); XtService service = getService(platform);