diff options
author | Sven Gothel <[email protected]> | 2023-05-17 16:48:10 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-05-17 16:48:10 +0200 |
commit | f1f21406540f74a2d002b11ed039eb8dcf4ff64f (patch) | |
tree | 166fe0a5bc141296402456e3ba27082abadc14b8 /src/java/jogamp | |
parent | e7f6807d42d9821e42ee4f8ae3ce9fd8ef2d4e31 (diff) |
ALAudioSink.dequeueBuffer(): wait == true: Fix sleep cycle and use sleep(1) if slept long enough but giving better threading perf for openal-soft
This with exclusive context gives us no distortion at 3x 12ms frames,
reduced from 3x 16ms. See Synth02AL.
Diffstat (limited to 'src/java/jogamp')
-rw-r--r-- | src/java/jogamp/openal/util/ALAudioSink.java | 70 |
1 files changed, 47 insertions, 23 deletions
diff --git a/src/java/jogamp/openal/util/ALAudioSink.java b/src/java/jogamp/openal/util/ALAudioSink.java index bd8c4ae..a801ce9 100644 --- a/src/java/jogamp/openal/util/ALAudioSink.java +++ b/src/java/jogamp/openal/util/ALAudioSink.java @@ -30,11 +30,13 @@ package jogamp.openal.util; import java.nio.ByteBuffer; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import jogamp.openal.Debug; import com.jogamp.common.ExceptionUtils; import com.jogamp.common.av.AudioSink; +import com.jogamp.common.os.Clock; import com.jogamp.common.util.LFRingbuffer; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.Ringbuffer; @@ -99,6 +101,7 @@ public class ALAudioSink implements AudioSink { // private ALAudioFrame[] alFrames = null; private int[] alBufferNames = null; + private int avgFrameDuration = 0; // [ms] private int frameGrowAmount = 0; private int frameLimit = 0; @@ -438,6 +441,7 @@ public class ALAudioSink implements AudioSink { destroyBuffers(); { final float useFrameDuration = frameDuration > 1f ? frameDuration : AudioSink.DefaultFrameDuration; + avgFrameDuration = (int) useFrameDuration; final int initialFrameCount = requestedFormat.getFrameCount( initialQueueSize > 0 ? initialQueueSize : AudioSink.DefaultInitialQueueSize, useFrameDuration); // frameDuration, int initialQueueSize, int queueGrowAmount, int queueLimit) { @@ -613,31 +617,54 @@ public class ALAudioSink implements AudioSink { if( alBufferBytesQueued > 0 ) { final int releaseBufferLimes = Math.max(1, alFramesPlaying.size() / 4 ); final int[] val=new int[1]; + final int avgBufferDura = chosenFormat.getBytesDuration( alBufferBytesQueued / alFramesPlaying.size() ); + final int sleepLimes = releaseBufferLimes * avgBufferDura; int i=0; + int slept = 0; + int releasedBuffers = 0; + final long t0 = DEBUG ? Clock.currentNanos() : 0; do { + val[0] = 0; al.alGetSourcei(alSource[0], ALConstants.AL_BUFFERS_PROCESSED, val, 0); alErr = al.alGetError(); if( ALConstants.AL_NO_ERROR != alErr ) { throw new RuntimeException(getThreadName()+": ALError "+toHexString(alErr)+" while quering processed buffers at source. "+this); } - if( wait && val[0] < releaseBufferLimes ) { + releasedBuffers += val[0]; + if( wait && releasedBuffers < releaseBufferLimes ) { i++; - // clip wait at [2 .. 100] ms - final int avgBufferDura = chosenFormat.getBytesDuration( alBufferBytesQueued / alFramesPlaying.size() ); - final int sleep = Math.max(2, Math.min(100, releaseBufferLimes * avgBufferDura)); - if( DEBUG ) { - System.err.println(getThreadName()+": ALAudioSink: Dequeue.wait["+i+"]: avgBufferDura "+avgBufferDura+", releaseBufferLimes "+releaseBufferLimes+", sleep "+sleep+" ms, playImpl "+(ALConstants.AL_PLAYING == getSourceState(false))+", processed "+val[0]+", "+this); - } - unlockContext(); - try { - Thread.sleep( sleep - 1 ); - } catch (final InterruptedException e) { - } finally { - lockContext(); + // clip wait at [avgFrameDuration .. 100] ms + final int sleep = Math.max(avgFrameDuration, Math.min(100, releaseBufferLimes-releasedBuffers * avgBufferDura)); + if( slept + sleep <= sleepLimes ) { + if( DEBUG ) { + System.err.println(getThreadName()+": ALAudioSink: Dequeue.wait-sleep["+i+"]: avgBufferDura "+avgBufferDura+", releaseBuffers "+releasedBuffers+"/"+releaseBufferLimes+", sleep "+sleep+"/"+slept+"/"+sleepLimes+" ms, playImpl "+(ALConstants.AL_PLAYING == getSourceState(false))+", processed "+val[0]+", "+shortString()); + } + unlockContext(); + try { + Thread.sleep( sleep ); + slept += sleep; + } catch (final InterruptedException e) { + } finally { + lockContext(); + } + } else { + // Empirical best behavior w/ openal-soft (sort of needs min ~21ms to complete processing a buffer even if period < 20ms?) + unlockContext(); + try { + Thread.sleep( 1 ); + slept += 1; + } catch (final InterruptedException e) { + } finally { + lockContext(); + } } } - } while ( wait && val[0] < releaseBufferLimes && alBufferBytesQueued > 0 ); - releaseBufferCount = val[0]; + } while ( wait && releasedBuffers < releaseBufferLimes && alBufferBytesQueued > 0 ); + releaseBufferCount = releasedBuffers; + if( DEBUG ) { + final long t1 = Clock.currentNanos(); + System.err.println(getThreadName()+": ALAudioSink: Dequeue.wait-done["+i+"]: "+TimeUnit.NANOSECONDS.toMillis(t1-t0)+" ms, avgBufferDura "+avgBufferDura+", releaseBuffers "+releaseBufferCount+"/"+releaseBufferLimes+", slept "+slept+" ms, playImpl "+(ALConstants.AL_PLAYING == getSourceState(false))+", processed "+val[0]+", "+shortString()); + } } else { releaseBufferCount = 0; } @@ -741,20 +768,17 @@ public class ALAudioSink implements AudioSink { lockContext(); try { final int duration = chosenFormat.getBytesDuration(byteCount); - final boolean dequeueDone; if( alFramesAvail.isEmpty() ) { // try to dequeue w/o waiting first - dequeueDone = dequeueBuffer(false, pts, duration) > 0; + dequeueBuffer(false, pts, duration); if( alFramesAvail.isEmpty() ) { // try to grow growBuffers(); } - } else { - dequeueDone = false; - } - if( !dequeueDone && alFramesPlaying.size() > 0 ) { // dequeue only possible if playing .. - final boolean wait = isPlayingImpl0() && alFramesAvail.isEmpty(); // possible if grow failed or already exceeds it's limit! - dequeueBuffer(wait, pts, duration); + if( alFramesAvail.isEmpty() && alFramesPlaying.size() > 0 && isPlayingImpl0() ) { + // possible if grow failed or already exceeds it's limit - only possible if playing .. + dequeueBuffer(true /* wait */, pts, duration); + } } alFrame = alFramesAvail.get(); |