[WIP]-39 updates to resolve issue with stopping channel streams.

This commit is contained in:
Denny
2018-04-22 04:44:35 -04:00
parent 7a9f705517
commit e395d737f8
15 changed files with 206 additions and 64 deletions

View File

@@ -33,7 +33,7 @@ public class ChannelCalculator
* from an index where the frequency may exist either at the overlapping boundary of two indexes, or in the middle
* of the wrap-around (N/2) index.
*/
private enum IndexBoundaryPolicy
public enum IndexBoundaryPolicy
{
ADJUST_POSITIVE,
ADJUST_NEGATIVE

View File

@@ -31,6 +31,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChannelizer
@@ -132,11 +133,17 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
init(filterTaps);
}
/**
* Starts sample processing
*/
public void start()
{
mIFFTProcessor.start();
}
/**
* Stops sample processing.
*/
public void stop()
{
mIFFTProcessor.stop();
@@ -504,6 +511,22 @@ public class ComplexPolyphaseChannelizerM2 extends AbstractComplexPolyphaseChann
}
});
}
/**
* Clears any buffers from the dispatch/processing queue. Overrides the parent method so that we can set
* the user count to 0 to allow the buffer to be reclaimed.
*/
protected Collection<ReusableChannelResultsBuffer> clearQueue()
{
Collection<ReusableChannelResultsBuffer> buffersToDispose = super.clearQueue();
for(ReusableChannelResultsBuffer buffer: buffersToDispose)
{
buffer.clearUserCount();
}
return buffersToDispose;
}
}
public static void main(String[] args)

View File

@@ -23,6 +23,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -138,9 +139,11 @@ public class ContinuousBufferProcessor<E> implements Listener<E>
/**
* Clears any buffers from the queue
*/
protected void clearQueue()
protected Collection<E> clearQueue()
{
mQueue.clear();
Collection<E> clearedElements = new ArrayList<>();
mQueue.drainTo(clearedElements);
return clearedElements;
}
/**

View File

@@ -26,6 +26,7 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.IReusableBufferProvider;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.Source;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.TunerController;
@@ -134,21 +135,34 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
*/
public TunerChannelSource getChannel(TunerChannel tunerChannel)
{
mLog.debug("Getting channel: " + tunerChannel.toString());
PolyphaseChannelSource channelSource = null;
try
{
List<Integer> polyphaseIndexes = mChannelCalculator.getChannelIndexes(tunerChannel);
StringBuilder sb = new StringBuilder();
sb.append("Channel Indexes - ");
for(int index: polyphaseIndexes)
{
sb.append(index).append(":").append((long)mChannelCalculator.getIndexCenterFrequency(index,
ChannelCalculator.IndexBoundaryPolicy.ADJUST_POSITIVE)).append(" ");
}
mLog.debug(sb.toString());
IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
mLog.debug("Channel Ouput Processor: " + outputProcessor.getClass());
if(outputProcessor != null)
{
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate());
mChannelCalculator.getChannelSampleRate(), centerFrequency);
mChannelSources.add(channelSource);
mSourceEventBroadcaster.broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
}
}
catch(IllegalArgumentException iae)
@@ -176,8 +190,10 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
if(outputProcessor != null)
{
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate());
mChannelCalculator.getChannelSampleRate(), centerFrequency);
}
}
catch(IllegalArgumentException iae)
@@ -227,8 +243,12 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
{
synchronized(mBufferProcessor)
{
mPolyphaseChannelizer.addChannel(channelSource);
//Note: the polyphase channel source has already been added to the mChannelSources in getChannel() method
mPolyphaseChannelizer.addChannel(channelSource);
mSourceEventBroadcaster.broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
//If this is the first channel, register to start the sample buffers flowing
if(mPolyphaseChannelizer.getRegisteredChannelCount() == 1)
{
mReusableBufferProvider.addBufferListener(mBufferProcessor);
@@ -249,8 +269,10 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
synchronized(mBufferProcessor)
{
mChannelSources.remove(channelSource);
mPolyphaseChannelizer.removeChannel(channelSource);
mSourceEventBroadcaster.broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
//If this is the last/only channel, deregister to stop the sample buffers
if(mPolyphaseChannelizer.getRegisteredChannelCount() == 0)
{
mReusableBufferProvider.removeBufferListener(mBufferProcessor);
@@ -532,9 +554,18 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
(sourceEvent.hasSource() ? sourceEvent.getSource().getClass() : "null source"));
}
break;
case REQUEST_SOURCE_DISPOSE:
Source source = sourceEvent.getSource();
if(source instanceof PolyphaseChannelSource)
{
source.dispose();
}
break;
default:
mLog.error("Received unrecognized source event from polyphase channel source [" +
sourceEvent.getEvent() + "]");
break;
}
}
}

View File

@@ -33,8 +33,8 @@ public class PolyphaseChannelSource extends TunerChannelSource
private ReusableBufferAssembler mReusableBufferAssembler;
private IPolyphaseChannelOutputProcessor mPolyphaseChannelOutputProcessor;
private double mChannelSampleRate;
private long mCenterFrequency;
private long mFrequencyCorrection;
private long mIndexCenterFrequency;
private long mChannelFrequencyCorrection;
/**
* Polyphase channelizer tuner channel source implementation. Adapts the channel array output samples from the
@@ -45,14 +45,17 @@ public class PolyphaseChannelSource extends TunerChannelSource
* @param outputProcessor - to process polyphase channelizer channel results into a channel stream
* @param producerSourceEventListener to receive source event requests (e.g. start/stop sample stream)
* @param channelSampleRate for the downstream sample output
* @param centerFrequency of the incoming polyphase channel(s)
*/
public PolyphaseChannelSource(TunerChannel tunerChannel, IPolyphaseChannelOutputProcessor outputProcessor,
Listener<SourceEvent> producerSourceEventListener, double channelSampleRate)
Listener<SourceEvent> producerSourceEventListener, double channelSampleRate,
long centerFrequency)
{
super(producerSourceEventListener, tunerChannel);
mPolyphaseChannelOutputProcessor = outputProcessor;
mChannelSampleRate = channelSampleRate;
mReusableBufferAssembler = new ReusableBufferAssembler(2500, mChannelSampleRate);
setFrequency(centerFrequency);
}
/**
@@ -114,10 +117,10 @@ public class PolyphaseChannelSource extends TunerChannelSource
//Finally, setup the frequency offset for the output processor and reset the frequency correction value
//to allow consumers to adjust and calculate a new frequency correction value, if needed.
mCenterFrequency = frequency;
mFrequencyCorrection = 0;
mIndexCenterFrequency = frequency;
mChannelFrequencyCorrection = 0;
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mFrequencyCorrection));
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
}
}
@@ -158,13 +161,22 @@ public class PolyphaseChannelSource extends TunerChannelSource
@Override
public void dispose()
{
mLog.info("Polyphase channel source received request to dispose");
if(mReusableBufferAssembler != null)
{
mReusableBufferAssembler.dispose();
}
if(mPolyphaseChannelOutputProcessor != null)
{
mPolyphaseChannelOutputProcessor.dispose();
mPolyphaseChannelOutputProcessor = null;
}
}
@Override
public long getFrequencyCorrection()
public long getChannelFrequencyCorrection()
{
return mFrequencyCorrection;
return mChannelFrequencyCorrection;
}
/**
@@ -173,26 +185,26 @@ public class PolyphaseChannelSource extends TunerChannelSource
*
* @param value to apply for frequency correction in hertz
*/
protected void setFrequencyCorrection(long value)
protected void setChannelFrequencyCorrection(long value)
{
mFrequencyCorrection = value;
mChannelFrequencyCorrection = value;
updateFrequencyOffset();
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mFrequencyCorrection));
broadcastConsumerSourceEvent(SourceEvent.frequencyCorrectionChange(mChannelFrequencyCorrection));
}
/**
* Sets the center frequency for the incoming sample stream channel results and resets frequency correction to zero.
* Sets the center frequency for this channel.frequency for the incoming sample stream channel results and resets frequency correction to zero.
* @param frequency in hertz
*/
@Override
protected void setFrequency(long frequency)
{
mLog.debug("Center Frequency set to: " + frequency + " for channel " + getTunerChannel().toString());
mCenterFrequency = frequency;
mLog.debug("Index Center Frequency set to: " + frequency + " for channel " + getTunerChannel().toString());
mIndexCenterFrequency = frequency;
//Set frequency correction to zero to trigger an update to the mixer and allow downstream monitors to
//recalculate the frequency error correction again
setFrequencyCorrection(0);
setChannelFrequencyCorrection(0);
}
@Override
@@ -210,7 +222,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
*/
private long getFrequencyOffset()
{
return getTunerChannel().getFrequency() - mCenterFrequency + mFrequencyCorrection;
return getTunerChannel().getFrequency() - mIndexCenterFrequency + mChannelFrequencyCorrection;
}
/**
@@ -222,6 +234,7 @@ public class PolyphaseChannelSource extends TunerChannelSource
{
synchronized(mPolyphaseChannelOutputProcessor)
{
mLog.debug("Setting output processor frequency offset to: " + getFrequencyOffset());
mPolyphaseChannelOutputProcessor.setFrequencyOffset(getFrequencyOffset());
}
}

View File

@@ -40,7 +40,6 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
private int mMaxResultsToProcess;
private int mInputChannelCount;
//TODO: swap this out and use the LowPhaseNoiseOscillator
private IOscillator mFrequencyCorrectionMixer;
private boolean mFrequencyCorrectionEnabled;
@@ -55,12 +54,23 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
public ChannelOutputProcessor(int inputChannelCount, double sampleRate)
{
mInputChannelCount = inputChannelCount;
//TODO: swap this out and use the LowPhaseNoiseOscillator
mFrequencyCorrectionMixer = new Oscillator(0, sampleRate);
mMaxResultsToProcess = (int)(sampleRate / 10) * 2; //process at 100 millis interval, twice the expected inflow rate
mChannelResultsQueue = new OverflowableTransferQueue<>((int)(sampleRate * 3), (int)(sampleRate * 0.5));
}
public void dispose()
{
if(mChannelResultsQueue != null)
{
mChannelResultsQueue.dispose();
mChannelResultsQueue = null;
}
}
/**
* Sets the frequency offset to apply to the incoming samples to mix the desired signal to baseband.
* @param frequencyOffset in hertz
@@ -68,7 +78,7 @@ public abstract class ChannelOutputProcessor implements IPolyphaseChannelOutputP
@Override
public void setFrequencyOffset(long frequencyOffset)
{
mLog.debug("Setting frequency offset to: " + frequencyOffset);
mLog.debug("Setting frequency offset to: " + frequencyOffset + " for class:" + this.getClass());
mFrequencyCorrectionMixer.setFrequency(frequencyOffset);
mFrequencyCorrectionEnabled = (frequencyOffset != 0);
}

View File

@@ -70,4 +70,7 @@ public interface IPolyphaseChannelOutputProcessor
* @param source to receive overflow notifications
*/
void setSourceOverflowListener(Source source);
void dispose();
}