Resolves #393 - Adds support for recording demodulated (raw) bitstream

buffers.  None of the decoders currently support this yet, but the P25
will be updated to provide bitstream output for recording.

Renames the ReusableBuffer class to ReusableFloatBuffer for
consistency.
This commit is contained in:
Denny
2018-08-11 08:02:58 -04:00
parent d7e018f66e
commit 5f8f2ec330
64 changed files with 936 additions and 407 deletions

View File

@@ -1,6 +1,6 @@
package io.github.dsheirer.sample;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -56,7 +56,7 @@ public class ConversionUtils
* Converts the float samples in a complex buffer to a little endian 16-bit
* buffer
*/
public static ByteBuffer convertToSigned16BitSamples(ReusableBuffer buffer)
public static ByteBuffer convertToSigned16BitSamples(ReusableFloatBuffer buffer)
{
return convertToSigned16BitSamples(buffer.getSamples());
}

View File

@@ -15,9 +15,9 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public abstract class AbstractSampleAdapter<T extends ReusableBuffer>
public abstract class AbstractSampleAdapter<T extends ReusableFloatBuffer>
{
public abstract T convert(byte[] sampleBytes);
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import io.github.dsheirer.source.mixer.MixerChannel;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
@@ -46,10 +46,10 @@ public class RealChannelShortAdapter extends RealSampleAdapter
}
@Override
public ReusableBuffer convert(byte[] samples)
public ReusableFloatBuffer convert(byte[] samples)
{
ReusableBuffer reusableBuffer = getBuffer(samples.length / 4);
float[] convertedSamples = reusableBuffer.getSamples();
ReusableFloatBuffer reusableFloatBuffer = getBuffer(samples.length / 4);
float[] convertedSamples = reusableFloatBuffer.getSamples();
mByteBuffer = ByteBuffer.wrap(samples);
@@ -76,7 +76,7 @@ public class RealChannelShortAdapter extends RealSampleAdapter
}
}
return reusableBuffer;
return reusableFloatBuffer;
}
/**

View File

@@ -15,10 +15,10 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableBuffer>
public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableFloatBuffer>
{
private ReusableBufferQueue mReusableBufferQueue;
@@ -32,7 +32,7 @@ public abstract class RealSampleAdapter extends AbstractSampleAdapter<ReusableBu
mReusableBufferQueue = new ReusableBufferQueue(debugName);
}
protected ReusableBuffer getBuffer(int size)
protected ReusableFloatBuffer getBuffer(int size)
{
return mReusableBufferQueue.getBuffer(size);
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.adapter;
import io.github.dsheirer.sample.buffer.ReusableBuffer;
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -40,10 +40,10 @@ public class RealShortAdapter extends RealSampleAdapter
}
@Override
public ReusableBuffer convert(byte[] samples)
public ReusableFloatBuffer convert(byte[] samples)
{
ReusableBuffer reusableBuffer = getBuffer(samples.length / 2);
float[] convertedSamples = reusableBuffer.getSamples();
ReusableFloatBuffer reusableFloatBuffer = getBuffer(samples.length / 2);
float[] convertedSamples = reusableFloatBuffer.getSamples();
int pointer = 0;
@@ -58,7 +58,7 @@ public class RealShortAdapter extends RealSampleAdapter
pointer++;
}
return reusableBuffer;
return reusableFloatBuffer;
}
/**

View File

@@ -19,5 +19,5 @@ import io.github.dsheirer.sample.Listener;
public interface IReusableBufferListener
{
Listener<ReusableBuffer> getReusableBufferListener();
Listener<ReusableFloatBuffer> getReusableBufferListener();
}

View File

@@ -22,7 +22,7 @@ public interface IReusableBufferProvider
/**
* Adds the listener to receive complex buffer samples
*/
void setBufferListener(Listener<ReusableBuffer> listener);
void setBufferListener(Listener<ReusableFloatBuffer> listener);
/**
* Removes the listener from receiving complex buffer samples

View File

@@ -0,0 +1,23 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample.buffer;
import io.github.dsheirer.sample.Listener;
public interface IReusableByteBufferListener<ReusableByteBuffer>
{
Listener<ReusableByteBuffer> getReusableByteBufferListener();
}

View File

@@ -0,0 +1,36 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample.buffer;
import io.github.dsheirer.sample.Listener;
public interface IReusableByteBufferProvider
{
/**
* Adds the listener to receive complex buffer samples
*/
void setBufferListener(Listener<ReusableByteBuffer> listener);
/**
* Removes the listener from receiving complex buffer samples
*/
void removeBufferListener(Listener<ReusableByteBuffer> listener);
/**
* Indicates if there are any complex buffer listeners registered
*/
boolean hasBufferListeners();
}

View File

@@ -113,16 +113,16 @@ public class ReusableAudioPacket extends AbstractReusableBuffer
* Loads a copy of the float sample data from the reusable buffer into this audio packet, resizing the
* internal audio sample buffer as necessary.
*
* @param reusableBuffer to load audio sample data from
* @param reusableFloatBuffer to load audio sample data from
*/
public void loadAudioFrom(ReusableBuffer reusableBuffer)
public void loadAudioFrom(ReusableFloatBuffer reusableFloatBuffer)
{
if(reusableBuffer.getSamples().length != mAudioSamples.length)
if(reusableFloatBuffer.getSamples().length != mAudioSamples.length)
{
resize(reusableBuffer.getSamples().length);
resize(reusableFloatBuffer.getSamples().length);
}
System.arraycopy(reusableBuffer.getSamples(), 0, mAudioSamples, 0, reusableBuffer.getSamples().length);
System.arraycopy(reusableFloatBuffer.getSamples(), 0, mAudioSamples, 0, reusableFloatBuffer.getSamples().length);
}
/**

View File

@@ -19,16 +19,16 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.real.RealSampleListener;
/**
* Assembles single float samples into a ReusableBuffer containing an array of floats
* Assembles single float samples into a ReusableFloatBuffer containing an array of floats
*/
public class ReusableBufferAssembler implements RealSampleListener
{
private int mBufferSize;
private int mBufferPointer;
private ReusableBuffer mCurrentBuffer;
private ReusableFloatBuffer mCurrentBuffer;
private ReusableBufferQueue mReusableBufferQueue = new ReusableBufferQueue("Real");
private Listener<ReusableBuffer> mListener;
private Listener<ReusableFloatBuffer> mListener;
public ReusableBufferAssembler(int bufferSize)
{
@@ -73,7 +73,7 @@ public class ReusableBufferAssembler implements RealSampleListener
}
}
public void setListener(Listener<ReusableBuffer> listener)
public void setListener(Listener<ReusableFloatBuffer> listener)
{
mListener = listener;
}

View File

@@ -18,7 +18,7 @@ package io.github.dsheirer.sample.buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableBuffer>
public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableFloatBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ReusableBufferQueue.class);
@@ -35,13 +35,13 @@ public class ReusableBufferQueue extends AbstractReusableBufferQueue<ReusableBuf
* @param size of the samples that will be loaded into the buffer
* @return a reusable buffer
*/
public ReusableBuffer getBuffer(int size)
public ReusableFloatBuffer getBuffer(int size)
{
ReusableBuffer buffer = getRecycledBuffer();
ReusableFloatBuffer buffer = getRecycledBuffer();
if(buffer == null)
{
buffer = new ReusableBuffer(this, new float[size]);
buffer = new ReusableFloatBuffer(this, new float[size]);
buffer.setDebugName("Owner:" + getDebugName());
incrementBufferCount();
}

View File

@@ -0,0 +1,97 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample.buffer;
import org.apache.commons.lang3.Validate;
public class ReusableByteBuffer extends AbstractReusableBuffer
{
private byte[] mSamples;
/**
* Creates a reusable, timestamped byte buffer using the specified time in milliseconds.
*
* NOTE: reusability of this buffer requires strict user count tracking. Each component that receives this
* buffer should not modify the buffer contents. Each component should also increment the user count before
* sending this buffer to another component and should decrement the user count when finished using this buffer.
*
* @param bufferDisposedListener to be notified when all consumers/users are finished using the buffer
* @param bytes of data
* @param timestamp in millis for the buffer
*/
ReusableByteBuffer(IReusableBufferDisposedListener bufferDisposedListener, byte[] bytes, long timestamp)
{
super(bufferDisposedListener, timestamp);
mSamples = bytes;
Validate.notNull(bufferDisposedListener, "Reusable Byte Buffer Listener cannot be null");
}
/**
* Constructs a timestamped byte buffer using the current system time in milliseconds.
*
* NOTE: reusability of this buffer requires strict user count tracking. Each component that receives this
* buffer should not modify the buffer contents. Each component should also increment the user count before
* sending this buffer to another component and should decrement the user count when finished using this buffer.
*
* @param bufferDisposedListener to be notified when all consumers are finished using the buffer
* @param bytes of data
*/
public ReusableByteBuffer(IReusableBufferDisposedListener bufferDisposedListener, byte[] bytes)
{
this(bufferDisposedListener, bytes, System.currentTimeMillis());
}
/**
* Samples for this buffer
*/
public byte[] getBytes()
{
return mSamples;
}
/**
* Creates a copy of the samples from this buffer
*/
public byte[] getSamplesCopy()
{
byte[] bytes = getBytes();
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
return copy;
}
/**
* Number of bytes contained in this buffer
*/
public int getSampleCount()
{
return getBytes().length;
}
/**
* Resizes the internal array to the size argument
*
* @param size for the internal array
*/
protected void resize(int size)
{
if(mSamples.length != size)
{
mSamples = new byte[size];
}
}
}

View File

@@ -0,0 +1,54 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
package io.github.dsheirer.sample.buffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReusableByteBufferQueue extends AbstractReusableBufferQueue<ReusableByteBuffer>
{
private final static Logger mLog = LoggerFactory.getLogger(ReusableByteBufferQueue.class);
public ReusableByteBufferQueue(String debugName)
{
super(debugName);
}
/**
* Returns a reusable buffer from an internal recycling queue, or creates a new buffer if there are currently no
* buffers available for reuse. The user count is set to one and must be managed throughout the lifecycle
* of the buffer.
*
* @param size of the samples that will be loaded into the buffer
* @return a reusable buffer
*/
public ReusableByteBuffer getBuffer(int size)
{
ReusableByteBuffer buffer = getRecycledBuffer();
if(buffer == null)
{
buffer = new ReusableByteBuffer(this, new byte[size]);
buffer.setDebugName("Owner:" + getDebugName());
incrementBufferCount();
}
buffer.resize(size);
buffer.incrementUserCount();
return buffer;
}
}

View File

@@ -15,7 +15,7 @@
******************************************************************************/
package io.github.dsheirer.sample.buffer;
public class ReusableComplexBuffer extends ReusableBuffer
public class ReusableComplexBuffer extends ReusableFloatBuffer
{
/**
* Creates a reusable, timestamped complex buffer using the specified time in milliseconds.

View File

@@ -19,7 +19,7 @@ import org.apache.commons.lang3.Validate;
import java.nio.FloatBuffer;
public class ReusableBuffer extends AbstractReusableBuffer
public class ReusableFloatBuffer extends AbstractReusableBuffer
{
private float[] mSamples;
@@ -34,7 +34,7 @@ public class ReusableBuffer extends AbstractReusableBuffer
* @param samples of data
* @param timestamp in millis for the buffer
*/
ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples, long timestamp)
ReusableFloatBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples, long timestamp)
{
super(bufferDisposedListener, timestamp);
mSamples = samples;
@@ -79,7 +79,7 @@ public class ReusableBuffer extends AbstractReusableBuffer
* @param bufferDisposedListener to be notified when all consumers are finished using the buffer
* @param samples of data
*/
public ReusableBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples)
public ReusableFloatBuffer(IReusableBufferDisposedListener bufferDisposedListener, float[] samples)
{
this(bufferDisposedListener, samples, System.currentTimeMillis());
}