mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
Bugfix-#2383-audio-trapped-in-output-buffer-of-resampler (#2384)
Closes #2383 Resolves issue with audio samples trapped in the resampler output buffer. Includes improvement provided by @bazineta
This commit is contained in:
@@ -21,8 +21,6 @@ package io.github.dsheirer.dsp.filter.resample;
|
|||||||
import com.laszlosystems.libresample4j.Resampler;
|
import com.laszlosystems.libresample4j.Resampler;
|
||||||
import com.laszlosystems.libresample4j.SampleBuffers;
|
import com.laszlosystems.libresample4j.SampleBuffers;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
@@ -34,7 +32,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class RealResampler
|
public class RealResampler
|
||||||
{
|
{
|
||||||
protected static final Logger mLog = LoggerFactory.getLogger(RealResampler.class);
|
|
||||||
|
|
||||||
private Resampler mResampler;
|
private Resampler mResampler;
|
||||||
private Listener<float[]> mResampledListener;
|
private Listener<float[]> mResampledListener;
|
||||||
@@ -109,6 +106,19 @@ public class RealResampler
|
|||||||
{
|
{
|
||||||
mBufferManager.load(samples);
|
mBufferManager.load(samples);
|
||||||
mResampler.process(mResampleFactor, mBufferManager, lastBatch);
|
mResampler.process(mResampleFactor, mBufferManager, lastBatch);
|
||||||
|
|
||||||
|
if(lastBatch)
|
||||||
|
{
|
||||||
|
mBufferManager.flushPartialOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes any buffered resampler output for the current stream.
|
||||||
|
*/
|
||||||
|
public void flush()
|
||||||
|
{
|
||||||
|
resample(new float[0], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,19 +191,46 @@ public class RealResampler
|
|||||||
public void consumeOutput(float[] samples, int offset, int length)
|
public void consumeOutput(float[] samples, int offset, int length)
|
||||||
{
|
{
|
||||||
mOutputBuffer.put(samples, offset, length);
|
mOutputBuffer.put(samples, offset, length);
|
||||||
|
dispatchFullOutputBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches any complete resampled output buffers.
|
||||||
|
*/
|
||||||
|
private void dispatchFullOutputBuffers()
|
||||||
|
{
|
||||||
while(mOutputBuffer.position() > mOutputArrayLength)
|
while(mOutputBuffer.position() > mOutputArrayLength)
|
||||||
{
|
{
|
||||||
float[] resampled = new float[mOutputArrayLength];
|
dispatchOutputBuffer(mOutputArrayLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mOutputBuffer.flip();
|
/**
|
||||||
mOutputBuffer.get(resampled);
|
* Flushes any remaining partial output by zero-padding to a full output buffer length.
|
||||||
mOutputBuffer.compact();
|
*/
|
||||||
|
public void flushPartialOutput()
|
||||||
|
{
|
||||||
|
if(mOutputBuffer.position() > 0)
|
||||||
|
{
|
||||||
|
dispatchOutputBuffer(mOutputBuffer.position());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(mResampledListener != null)
|
/**
|
||||||
{
|
* Dispatches the requested number of queued output samples, zero-padding the remainder of the fixed-size
|
||||||
mResampledListener.receive(resampled);
|
* output block when fewer than {@code mOutputArrayLength} samples are available.
|
||||||
}
|
*/
|
||||||
|
private void dispatchOutputBuffer(int sampleCount)
|
||||||
|
{
|
||||||
|
float[] resampled = new float[mOutputArrayLength];
|
||||||
|
|
||||||
|
mOutputBuffer.flip();
|
||||||
|
mOutputBuffer.get(resampled, 0, sampleCount);
|
||||||
|
mOutputBuffer.compact();
|
||||||
|
|
||||||
|
if(mResampledListener != null)
|
||||||
|
{
|
||||||
|
mResampledListener.receive(resampled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ public class NoiseSquelch implements INoiseSquelchController
|
|||||||
*/
|
*/
|
||||||
public boolean isSquelched()
|
public boolean isSquelched()
|
||||||
{
|
{
|
||||||
|
if(mSquelchOverride)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return mSquelch;
|
return mSquelch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,18 @@ public class NBFMDecoder extends SquelchControlDecoder implements ISourceEventLi
|
|||||||
|
|
||||||
//Send squelch controlled audio to the resampler and notify the decoder state that the call continues.
|
//Send squelch controlled audio to the resampler and notify the decoder state that the call continues.
|
||||||
mNoiseSquelch.setAudioListener(audio -> {
|
mNoiseSquelch.setAudioListener(audio -> {
|
||||||
mResampler.resample(audio);
|
// if squelch is closing (it hasn't propagated yet to mute the audio)
|
||||||
notifyCallContinuation();
|
// call the resampler with lastBatch set to true. This will zero pad the input buffer and ensure
|
||||||
|
// the output buffer gets emptied.
|
||||||
|
if(mNoiseSquelch.isSquelched())
|
||||||
|
{
|
||||||
|
mResampler.resample(audio, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mResampler.resample(audio); // this method will set lastBatch to false
|
||||||
|
notifyCallContinuation();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//Notify the decoder state of call starts and ends
|
//Notify the decoder state of call starts and ends
|
||||||
|
|||||||
Reference in New Issue
Block a user