mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
[WIP]-39 updates to resolve issue with stopping channel streams.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -70,4 +70,7 @@ public interface IPolyphaseChannelOutputProcessor
|
||||
* @param source to receive overflow notifications
|
||||
*/
|
||||
void setSourceOverflowListener(Source source);
|
||||
|
||||
|
||||
void dispose();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user