diff --git a/.idea/misc.xml b/.idea/misc.xml
index 48d2c0bec..dced427a5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/io/github/dsheirer/source/SourceEvent.java b/src/main/java/io/github/dsheirer/source/SourceEvent.java
index 41a761c41..e12ded964 100644
--- a/src/main/java/io/github/dsheirer/source/SourceEvent.java
+++ b/src/main/java/io/github/dsheirer/source/SourceEvent.java
@@ -197,7 +197,7 @@ public static SourceEvent errorState(Source source, String errorDescription)
/**
* Creates a new locked state change event
*/
- public static SourceEvent lockedState()
+ public static SourceEvent lockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED, 1);
}
@@ -205,7 +205,7 @@ public static SourceEvent lockedState()
/**
* Creates a new unlocked state change event
*/
- public static SourceEvent unlockedState()
+ public static SourceEvent unlockedSampleRateState()
{
return new SourceEvent(Event.NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED, 0);
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java
index 90671fb77..cede08c06 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java
@@ -36,11 +36,11 @@
import io.github.dsheirer.source.tuner.frequency.FrequencyController;
import io.github.dsheirer.source.tuner.frequency.FrequencyController.Tunable;
import io.github.dsheirer.source.tuner.manager.FrequencyErrorCorrectionManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.text.DecimalFormat;
import java.util.SortedSet;
+import java.util.concurrent.locks.ReentrantLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public abstract class TunerController implements Tunable, ISourceEventProcessor, ISourceEventListener,
INativeBufferProvider, Listener, ITunerErrorListener
@@ -70,6 +70,17 @@ public TunerController(ITunerErrorListener tunerErrorListener)
mFrequencyErrorCorrectionManager = new FrequencyErrorCorrectionManager(this);
}
+ /**
+ * Lock for the frequency controller. This should only be used by the channel source manager to lock access to the
+ * frequency controller while creating a channel source, to block multi-threaded access to the frequency controller
+ * which might put the center tuned frequency value in an indeterminant state.
+ * @return frequency controller lock
+ */
+ public ReentrantLock getFrequencyControllerLock()
+ {
+ return mFrequencyController.getFrequencyControllerLock();
+ }
+
/**
* Frequency correction manager for this tuner controller.
*/
@@ -182,29 +193,30 @@ public void process(SourceEvent sourceEvent ) throws SourceException
}
/**
- * Indicates if the frequency and sample rate controls are locked by another process. User interface controls
- * should monitor source events and check the locked state via this method to correctly render the enabled state
- * of the frequency and sample rate controls.
+ * Indicates if the sample rate control is locked by another process. User interface controls should monitor source
+ * events and check the locked state via this method to correctly render the enabled state of the sample rate control.
*
* @return true if the tuner controller is locked.
*/
- public boolean isLocked()
+ public boolean isLockedSampleRate()
{
- return mFrequencyController.isLocked();
+ //Note: this access is not protected by the mFrequencyControllerLock
+ return mFrequencyController.isSampleRateLocked();
}
/**
- * Sets the frequency and sample rate locked state to the locked argument value. This should only be changed
- * by a downstream consumer of samples to prevent users or other processes from modifying the center frequency
- * and/or sample rate of the tuner while processing samples.
+ * Sets the sample rate locked state to the locked argument value. This should only be changed by a downstream
+ * consumer of samples to prevent users or other processes from modifying the sample rate of the tuner while
+ * processing samples.
*
* @param locked true to indicate the tuner controller is in a locked state, otherwise false.
*/
- public void setLocked(boolean locked)
+ public void setLockedSampleRate(boolean locked)
{
try
{
- mFrequencyController.setLocked(locked);
+ //Note: this access is not protected by the mFrequencyControllerLock
+ mFrequencyController.setSampleRateLocked(locked);
}
catch(SourceException se)
{
@@ -214,6 +226,7 @@ public void setLocked(boolean locked)
public int getBandwidth()
{
+ //Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getBandwidth();
}
@@ -225,7 +238,15 @@ public int getBandwidth()
*/
public void setFrequency(long frequency) throws SourceException
{
- mFrequencyController.setFrequency(frequency);
+ try
+ {
+ getFrequencyControllerLock().lock();
+ mFrequencyController.setFrequency(frequency);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
}
/**
@@ -235,28 +256,73 @@ public void setFrequency(long frequency) throws SourceException
*/
public long getFrequency()
{
- return mFrequencyController.getFrequency();
+ long frequency;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ frequency = mFrequencyController.getFrequency();
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return frequency;
}
@Override
public boolean canTune(long frequency)
{
- return mFrequencyController.canTune(frequency);
+ boolean canTune;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ canTune = mFrequencyController.canTune(frequency);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return canTune;
}
public double getSampleRate()
{
+ //Note: this access is not protected by the mFrequencyControllerLock
return mFrequencyController.getSampleRate();
}
public double getFrequencyCorrection()
{
- return mFrequencyController.getFrequencyCorrection();
+ double correction;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ correction = mFrequencyController.getFrequencyCorrection();
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return correction;
}
public void setFrequencyCorrection(double correction) throws SourceException
{
- mFrequencyController.setFrequencyCorrection(correction);
+ try
+ {
+ getFrequencyControllerLock().lock();
+ mFrequencyController.setFrequencyCorrection(correction);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
}
/**
@@ -265,7 +331,19 @@ public void setFrequencyCorrection(double correction) throws SourceException
*/
public long getMinimumFrequency()
{
- return mFrequencyController.getMinimumFrequency();
+ long minimum;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ minimum = mFrequencyController.getMinimumFrequency();
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return minimum;
}
/**
@@ -274,7 +352,15 @@ public long getMinimumFrequency()
*/
public void setMinimumFrequency(long minimum)
{
- mFrequencyController.setMinimumFrequency(minimum);
+ try
+ {
+ getFrequencyControllerLock().lock();
+ mFrequencyController.setMinimumFrequency(minimum);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
}
/**
@@ -283,7 +369,19 @@ public void setMinimumFrequency(long minimum)
*/
public long getMaximumFrequency()
{
- return mFrequencyController.getMaximumFrequency();
+ long maximum;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ maximum = mFrequencyController.getMaximumFrequency();
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return maximum;
}
/**
@@ -292,17 +390,49 @@ public long getMaximumFrequency()
*/
public void setMaximumFrequency(long maximum)
{
- mFrequencyController.setMaximumFrequency(maximum);
+ try
+ {
+ getFrequencyControllerLock().lock();
+ mFrequencyController.setMaximumFrequency(maximum);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
}
public long getMinTunedFrequency() throws SourceException
{
- return mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
+ long minTuned;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ minTuned = mFrequencyController.getFrequency() - (getUsableBandwidth() / 2);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return minTuned;
}
public long getMaxTunedFrequency() throws SourceException
{
- return mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
+ long maxTuned;
+
+ try
+ {
+ getFrequencyControllerLock().lock();
+ maxTuned = mFrequencyController.getFrequency() + (getUsableBandwidth() / 2);
+ }
+ finally
+ {
+ getFrequencyControllerLock().unlock();
+ }
+
+ return maxTuned;
}
/**
@@ -425,7 +555,7 @@ public void setMeasuredFrequencyError(int measuredFrequencyError)
*/
public void addListener( ISourceEventProcessor processor )
{
- mFrequencyController.addListener(processor);
+ mFrequencyController.addSourceEventProcessor(processor);
}
/**
@@ -433,7 +563,7 @@ public void addListener( ISourceEventProcessor processor )
*/
public void removeListener( ISourceEventProcessor processor )
{
- mFrequencyController.removeFrequencyChangeProcessor(processor);
+ mFrequencyController.removeSourceEventProcessor(processor);
}
/**
diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java
index 0313db3c7..619201c0e 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerEditor.java
@@ -25,6 +25,9 @@
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,9 +43,6 @@
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.List;
/**
* Airspy tuner editor/controller
@@ -102,7 +102,7 @@ protected void tunerStatusUpdated()
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
- getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
+ getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
getTunerInfoButton().setEnabled(hasTuner());
updateGainComponents((hasTuner() && hasConfiguration()) ? getConfiguration().getGain() : null);
@@ -626,7 +626,7 @@ private AirspySampleRate getSampleRate(int value)
*/
private void updateSampleRateToolTip()
{
- if(hasTuner() && getTuner().getController().isLocked())
+ if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java b/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java
index f28c3b263..80ef95615 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/frequency/FrequencyController.java
@@ -22,12 +22,11 @@
import io.github.dsheirer.source.InvalidFrequencyException;
import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class FrequencyController
{
@@ -40,8 +39,12 @@ public class FrequencyController
private long mMaximumFrequency = 0;
private double mFrequencyCorrection = 0.0d;
private double mSampleRate = 0.0d;
- private boolean mLocked = false;
+ private boolean mSampleRateLocked = false;
private List mProcessors = new ArrayList<>();
+
+ /**
+ * Lock protecting access to frequency control plane, source event processor subscriptions and event broadcasting
+ */
private ReentrantLock mLock = new ReentrantLock();
/**
@@ -53,6 +56,15 @@ public FrequencyController(Tunable tunable)
mTunable = tunable;
}
+
+ /**
+ * Lock for controlling access to frequency control plane, event processor subscriptions and source event broadcasts.
+ */
+ public ReentrantLock getFrequencyControllerLock()
+ {
+ return mLock;
+ }
+
/**
* Prepare for disposal of this instance.
*/
@@ -63,36 +75,36 @@ public void dispose()
}
/**
- * Indicates if this frequency controller is locked by a remote process. A locked state indicates that neither
- * the frequency nor the sample rate should be changed. The remote process will typically be a downstream
+ * Indicates if the sample rate for this frequency controller is locked by a remote process. A locked state
+ * indicates that the sample rate cannot be changed. The remote process will typically be a downstream
* consumer of the data produced by the device being controlled (ie polyphase channelizer) that does not want
- * the sample rate or frequency to be changed while processing is ongoing.
+ * the sample rate to be changed while processing (ie channels have been allocated) is ongoing.
*
* @return true if locked or false if not locked.
*/
- public boolean isLocked()
+ public boolean isSampleRateLocked()
{
- return mLocked;
+ return mSampleRateLocked;
}
/**
* Sets the lock state for this frequency controller. Set to true when a consumer process requires that the
- * frequency and sample rate controls be locked so that only the singular consumer process makes changes. This
+ * sample rate control be locked so that only the single consumer process makes changes to the sample rate. This
* is primarily to lock down user interface controls when the polyphase channelizer is producing channels.
*
- * @param locked state
+ * @param sampleRateLocked state
*/
- public void setLocked(boolean locked) throws SourceException
+ public void setSampleRateLocked(boolean sampleRateLocked) throws SourceException
{
- mLocked = locked;
+ mSampleRateLocked = sampleRateLocked;
- if(mLocked)
+ if(mSampleRateLocked)
{
- broadcast(SourceEvent.lockedState());
+ broadcast(SourceEvent.lockedSampleRateState());
}
else
{
- broadcast(SourceEvent.unlockedState());
+ broadcast(SourceEvent.unlockedSampleRateState());
}
}
@@ -111,7 +123,7 @@ public void setSampleRate(int sampleRate) throws SourceException
{
if(sampleRate != mSampleRate)
{
- if(!mLocked)
+ if(!mSampleRateLocked)
{
mSampleRate = sampleRate;
@@ -284,7 +296,7 @@ public void setFrequencyCorrection(double correction) throws SourceException
/**
* Adds listener to receive frequency change events
*/
- public void addListener(ISourceEventProcessor processor)
+ public void addSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
@@ -304,7 +316,7 @@ public void addListener(ISourceEventProcessor processor)
/**
* Removes listener from receiving frequency change events
*/
- public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
+ public void removeSourceEventProcessor(ISourceEventProcessor processor)
{
mLock.lock();
diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java
index f547c90e6..66b6ce6cd 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerEditor.java
@@ -120,7 +120,7 @@ protected void tunerStatusUpdated()
getTunerStatusLabel().setText(status);
getButtonPanel().updateControls();
getFrequencyPanel().updateControls();
- getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
+ getSampleRateCombo().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
updateSampleRateToolTip();
getTunerInfoButton().setEnabled(hasTuner());
@@ -295,7 +295,7 @@ private JButton getTunerInfoButton()
*/
private void updateSampleRateToolTip()
{
- if(hasTuner() && getTuner().getController().isLocked())
+ if(hasTuner() && getTuner().getController().isLockedSampleRate())
{
mSampleRateCombo.setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/HeterodyneChannelSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/HeterodyneChannelSourceManager.java
index 55bdd571a..029aef870 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/manager/HeterodyneChannelSourceManager.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/manager/HeterodyneChannelSourceManager.java
@@ -93,38 +93,48 @@ public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecificat
return null;
}
- if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
+ TunerChannelSource source = null;
+
+ try
{
- try
+ mTunerController.getFrequencyControllerLock().lock();
+ if(CenterFrequencyCalculator.canTune(tunerChannel, mTunerController, mTunerChannels))
{
- //Attempt to create the channel source first, in case we get a filter design exception
- HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
- tunerChannel, mTunerController.getSampleRate(), channelSpecification);
+ try
+ {
+ //Attempt to create the channel source first, in case we get a filter design exception
+ HalfBandTunerChannelSource tunerChannelSource = new HalfBandTunerChannelSource(mChannelSourceEventProcessor,
+ tunerChannel, mTunerController.getSampleRate(), channelSpecification);
- //Add to the list of channel sources so that it will receive the tuner frequency change
- mChannelSources.add(tunerChannelSource);
+ //Add to the list of channel sources so that it will receive the tuner frequency change
+ mChannelSources.add(tunerChannelSource);
- //Set the current tuner frequency
- tunerChannelSource.setFrequency(mTunerController.getFrequency());
+ //Set the current tuner frequency
+ tunerChannelSource.setFrequency(mTunerController.getFrequency());
- //Add to the channel list and update the tuner center frequency as needed
- mTunerChannels.add(tunerChannel);
- updateTunerFrequency();
+ //Add to the channel list and update the tuner center frequency as needed
+ mTunerChannels.add(tunerChannel);
+ updateTunerFrequency();
- //Lock the tuner controller frequency and sample rate
- mTunerController.setLocked(true);
+ //Lock the tuner controller frequency and sample rate
+ mTunerController.setLockedSampleRate(true);
- broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
+ broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
- return tunerChannelSource;
- }
- catch(FilterDesignException fde)
- {
- mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
+ source = tunerChannelSource;
+ }
+ catch(FilterDesignException fde)
+ {
+ mLog.error("Error creating CIC tuner channel source - couldn't design cleanup filter", fde);
+ }
}
}
+ finally
+ {
+ mTunerController.getFrequencyControllerLock().unlock();
+ }
- return null;
+ return source;
}
@Override
@@ -294,7 +304,7 @@ public void receive(SourceEvent sourceEvent)
//Unlock the tuner controller if there are no more channels
if(getTunerChannelCount() == 0)
{
- mTunerController.setLocked(false);
+ mTunerController.setLockedSampleRate(false);
}
broadcast(SourceEvent.channelCountChange(getTunerChannelCount()));
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java
index f1aeeb540..a1584eb2e 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/manager/PassThroughSourceManager.java
@@ -82,18 +82,30 @@ public int getTunerChannelCount()
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
+
if(!mRunning)
{
return null;
}
- PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
- mTunerController, tunerChannel);
+ TunerChannelSource source = null;
+
+ try
+ {
+ mTunerController.getFrequencyControllerLock().lock();
+ PassThroughChannelSource channelSource = new PassThroughChannelSource(new SourceEventProxy(),
+ mTunerController, tunerChannel);
- mTunerChannels.add(tunerChannel);
- mTunerChannelSources.add(channelSource);
+ mTunerChannels.add(tunerChannel);
+ mTunerChannelSources.add(channelSource);
+ source = channelSource;
+ }
+ finally
+ {
+ mTunerController.getFrequencyControllerLock().unlock();
+ }
- return channelSource;
+ return source;
}
@Override
diff --git a/src/main/java/io/github/dsheirer/source/tuner/manager/PolyphaseChannelSourceManager.java b/src/main/java/io/github/dsheirer/source/tuner/manager/PolyphaseChannelSourceManager.java
index ac85201ce..323062083 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/manager/PolyphaseChannelSourceManager.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/manager/PolyphaseChannelSourceManager.java
@@ -25,12 +25,11 @@
import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
+import java.util.SortedSet;
import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.SortedSet;
-
/**
* PolyphaseChannelSourceManager is responsible for managing the tuner's center tuned frequency and providing access to
* polyphase tuner channel sources (ie DDCs). This class is responsible for determining IF a requested channel can
@@ -416,48 +415,56 @@ public int getTunerChannelCount()
@Override
public TunerChannelSource getSource(TunerChannel tunerChannel, ChannelSpecification channelSpecification)
{
- if(isTunable(tunerChannel))
- {
- //Get a new set of currently tuned channels
- SortedSet tunerChannels = getTunerChannels();
-
- //Add the requested channel to the list
- tunerChannels.add(tunerChannel);
+ TunerChannelSource tunerChannelSource = null;
- if(canTune(tunerChannels))
+ try
+ {
+ mTunerController.getFrequencyControllerLock().lock();
+ if(isTunable(tunerChannel))
{
- long currentCenterFrequency = mTunerController.getFrequency();
- long updatedCenterFrequency = 0;
+ //Get a new set of currently tuned channels
+ SortedSet tunerChannels = getTunerChannels();
- //Attempt to adjust the center frequency before we allocate the channel
- try
+ //Add the requested channel to the list
+ tunerChannels.add(tunerChannel);
+
+ if(canTune(tunerChannels))
{
- updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
+ long currentCenterFrequency = mTunerController.getFrequency();
+ long updatedCenterFrequency = 0;
- if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
+ //Attempt to adjust the center frequency before we allocate the channel
+ try
{
- mTunerController.setFrequency(updatedCenterFrequency);
- }
+ updatedCenterFrequency = getCenterFrequency(tunerChannels, currentCenterFrequency);
- //If we're successful to here, allocate the channel
- return mPolyphaseChannelManager.getChannel(tunerChannel);
- }
- catch(SourceException se)
- {
- //Tuner controller threw an error trying to tune to the updated frequency
- mLog.error("Error while updating tuner controller with new center frequency [" +
- updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
- }
- catch(IllegalArgumentException iae)
- {
- //Center frequency calculation failed
-// mLog.debug("Couldn't calculate new tuner center frequency for new tuner channel [" +
-// tunerChannel + "] unable to allocate new tuner channel");
+ if(updatedCenterFrequency != currentCenterFrequency && updatedCenterFrequency != 0)
+ {
+ mTunerController.setFrequency(updatedCenterFrequency);
+ }
+
+ //If we're successful to here, allocate the channel
+ tunerChannelSource = mPolyphaseChannelManager.getChannel(tunerChannel);
+ }
+ catch(SourceException se)
+ {
+ //Tuner controller threw an error trying to tune to the updated frequency
+ mLog.error("Error while updating tuner controller with new center frequency [" +
+ updatedCenterFrequency + "] - unable to allocate new tuner channel", se);
+ }
+ catch(IllegalArgumentException iae)
+ {
+ //Center frequency calculation failed
+ }
}
}
}
+ finally
+ {
+ mTunerController.getFrequencyControllerLock().unlock();
+ }
- return null;
+ return tunerChannelSource;
}
/**
@@ -474,7 +481,7 @@ public void process(SourceEvent sourceEvent)
broadcast(sourceEvent);
//Lock the frequency and sample rate controls on the tuner controller so users can't change them
//when the polyphase manager has channels allocated
- mTunerController.setLocked(getTunerChannelCount() > 0);
+ mTunerController.setLockedSampleRate(getTunerChannelCount() > 0);
break;
case NOTIFICATION_MEASURED_FREQUENCY_ERROR_SYNC_LOCKED:
//Rebroadcast these frequency measurement errors to the tuner and tuner controller
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
index 60ee7bc48..acca6164c 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerEditor.java
@@ -29,6 +29,8 @@
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KLNAGain;
import io.github.dsheirer.source.tuner.rtl.e4k.E4KEmbeddedTuner.E4KMixerGain;
import io.github.dsheirer.source.tuner.ui.TunerEditor;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,8 +43,6 @@
import javax.swing.JSeparator;
import javax.swing.SpinnerNumberModel;
import javax.usb.UsbException;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
/**
* E4000 tuner editor
@@ -383,7 +383,7 @@ private JButton getTunerInfoButton()
*/
private void updateSampleRateToolTip()
{
- if(hasTuner() && getTuner().getTunerController().isLocked())
+ if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
index 5589c510f..06c31a2c4 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerEditor.java
@@ -416,7 +416,7 @@ private JComboBox getMasterGainCombo()
*/
private void updateSampleRateToolTip()
{
- if(hasTuner() && getTuner().getTunerController().isLocked())
+ if(hasTuner() && getTuner().getTunerController().isLockedSampleRate())
{
getSampleRateCombo().setToolTipText("Sample Rate is locked. Disable decoding channels to unlock.");
}
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java
index 2ab1fa6fe..615a14103 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/DiscoveredTunerModel.java
@@ -25,10 +25,6 @@
import io.github.dsheirer.source.tuner.manager.DiscoveredUSBTuner;
import io.github.dsheirer.source.tuner.manager.IDiscoveredTunerStatusListener;
import io.github.dsheirer.source.tuner.manager.TunerStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.swing.table.AbstractTableModel;
import java.awt.EventQueue;
import java.text.DecimalFormat;
import java.util.ArrayList;
@@ -36,6 +32,10 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.table.AbstractTableModel;
/**
* Model for discovered tuners
@@ -449,7 +449,7 @@ public Object getValueAt(int rowIndex, int columnIndex)
if(discoveredTuner.hasTuner())
{
int channelCount = discoveredTuner.getTuner().getChannelSourceManager().getTunerChannelCount();
- return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLocked() ? "LOCKED)" : "UNLOCKED)");
+ return channelCount + " (" + (discoveredTuner.getTuner().getTunerController().isLockedSampleRate() ? "LOCKED)" : "UNLOCKED)");
}
else
{
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java
index 723d8c53e..0fe7106e6 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerEditor.java
@@ -619,8 +619,8 @@ public void updateControls()
{
getFrequencyControl().clearListeners();
getFrequencyControl().addListener(mFrequencyAndCorrectionChangeListener);
- getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLocked());
- getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLocked());
+ getFrequencyControl().setEnabled(hasTuner() && !getTuner().getTunerController().isLockedSampleRate());
+ getTunerLockedStatusLabel().setVisible(hasTuner() && getTuner().getTunerController().isLockedSampleRate());
getFrequencyCorrectionSpinner().setEnabled(hasTuner());
getAutoPPMCheckBox().setEnabled(hasTuner());
diff --git a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java
index 52bd416f8..b78351b69 100644
--- a/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java
+++ b/src/main/java/io/github/dsheirer/source/tuner/ui/TunerViewPanel.java
@@ -143,7 +143,7 @@ private void init()
if(selectedTuner != null && selectedTuner.hasTuner() && tunerEvent.getTuner() == selectedTuner.getTuner())
{
- mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLocked());
+ mDiscoveredTunerEditor.setTunerLockState(selectedTuner.getTuner().getTunerController().isLockedSampleRate());
}
}
}