mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 01:27:34 -05:00
#1210 Resolves issue of tuner instances can't be garbage collected due to retained references. Updates several of the tuner controller and tuner editor classes to add/invoke dispose() methods to clear retained instance references. (#1216)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
This commit is contained in:
@@ -39,7 +39,7 @@ public class AudioSegmentBroadcaster<T extends AudioSegment> extends Broadcaster
|
|||||||
@Override
|
@Override
|
||||||
public void broadcast(T audioSegment)
|
public void broadcast(T audioSegment)
|
||||||
{
|
{
|
||||||
for(Listener<T> listener : mListeners)
|
for(Listener<T> listener : getListeners())
|
||||||
{
|
{
|
||||||
audioSegment.incrementConsumerCount();
|
audioSegment.incrementConsumerCount();
|
||||||
listener.receive(audioSegment);
|
listener.receive(audioSegment);
|
||||||
|
|||||||
@@ -194,7 +194,10 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
|
|||||||
*/
|
*/
|
||||||
public void addListener(ISourceEventProcessor processor)
|
public void addListener(ISourceEventProcessor processor)
|
||||||
{
|
{
|
||||||
mProcessors.add(processor);
|
if(!mProcessors.contains(processor))
|
||||||
|
{
|
||||||
|
mProcessors.add(processor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ package io.github.dsheirer.sample;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcasts an item to multiple listeners
|
* Broadcasts an item to multiple listeners
|
||||||
@@ -32,8 +34,8 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(Broadcaster.class);
|
private final static Logger mLog = LoggerFactory.getLogger(Broadcaster.class);
|
||||||
private boolean mDebug;
|
private boolean mDebug;
|
||||||
|
private ReentrantLock mLock = new ReentrantLock();
|
||||||
protected List<Listener<T>> mListeners = new CopyOnWriteArrayList<>();
|
private List<Listener<T>> mListeners = new ArrayList<>();
|
||||||
|
|
||||||
public Broadcaster()
|
public Broadcaster()
|
||||||
{
|
{
|
||||||
@@ -64,7 +66,16 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
*/
|
*/
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
mListeners.clear();
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mListeners.clear();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,14 +86,6 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
return !mListeners.isEmpty();
|
return !mListeners.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the listener is currently registered with this broadcaster
|
|
||||||
*/
|
|
||||||
public boolean hasListener(Listener<T> listener)
|
|
||||||
{
|
|
||||||
return listener != null && mListeners.contains(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The count of listeners currently registered with this broadcaster
|
* The count of listeners currently registered with this broadcaster
|
||||||
*/
|
*/
|
||||||
@@ -96,7 +99,7 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
*/
|
*/
|
||||||
public List<Listener<T>> getListeners()
|
public List<Listener<T>> getListeners()
|
||||||
{
|
{
|
||||||
return mListeners;
|
return Collections.unmodifiableList(mListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,9 +109,21 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
*/
|
*/
|
||||||
public void addListener(Listener<T> listener)
|
public void addListener(Listener<T> listener)
|
||||||
{
|
{
|
||||||
if(listener != null && !mListeners.contains(listener))
|
if(listener != null)
|
||||||
{
|
{
|
||||||
mListeners.add(listener);
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!mListeners.contains(listener))
|
||||||
|
{
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +134,16 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
{
|
{
|
||||||
if(listener != null)
|
if(listener != null)
|
||||||
{
|
{
|
||||||
mListeners.remove(listener);
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mListeners.remove(listener);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +152,16 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
*/
|
*/
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
mListeners.clear();
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mListeners.clear();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -136,21 +169,30 @@ public class Broadcaster<T> implements Listener<T>
|
|||||||
*/
|
*/
|
||||||
public void broadcast(T t)
|
public void broadcast(T t)
|
||||||
{
|
{
|
||||||
if(mDebug)
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for(Listener<T> listener : mListeners)
|
if(mDebug)
|
||||||
{
|
{
|
||||||
mLog.debug("Sending [" + t + "] to listener [" + listener.getClass() + "]");
|
for(Listener<T> listener : mListeners)
|
||||||
listener.receive(t);
|
{
|
||||||
mLog.debug("Finished sending to listener [" + listener.getClass() + "]");
|
mLog.debug("Sending [" + t + "] to listener [" + listener.getClass() + "]");
|
||||||
|
listener.receive(t);
|
||||||
|
mLog.debug("Finished sending to listener [" + listener.getClass() + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(Listener<T> listener : mListeners)
|
||||||
|
{
|
||||||
|
listener.receive(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
finally
|
||||||
{
|
{
|
||||||
for(Listener<T> listener : mListeners)
|
mLock.unlock();
|
||||||
{
|
|
||||||
listener.receive(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,10 +110,17 @@ public abstract class Tuner implements ISourceEventProcessor, ITunerErrorListene
|
|||||||
if(getChannelSourceManager() != null)
|
if(getChannelSourceManager() != null)
|
||||||
{
|
{
|
||||||
getChannelSourceManager().stopAllChannels();
|
getChannelSourceManager().stopAllChannels();
|
||||||
|
getChannelSourceManager().dispose();
|
||||||
|
mChannelSourceManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcast(new TunerEvent(this, Event.NOTIFICATION_SHUTTING_DOWN));
|
broadcast(new TunerEvent(this, Event.NOTIFICATION_SHUTTING_DOWN));
|
||||||
getTunerController().stop();
|
getTunerController().stop();
|
||||||
|
getTunerController().dispose();
|
||||||
|
|
||||||
|
mTunerEventBroadcaster.clear();
|
||||||
|
mTunerFrequencyErrorMonitor = null;
|
||||||
|
mTunerErrorListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,13 +49,13 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster();
|
protected Broadcaster<INativeBuffer> mNativeBufferBroadcaster = new Broadcaster();
|
||||||
protected FrequencyController mFrequencyController;
|
protected FrequencyController mFrequencyController;
|
||||||
private int mMiddleUnusableHalfBandwidth;
|
private int mMiddleUnusableHalfBandwidth;
|
||||||
private double mUsableBandwidthPercentage;
|
|
||||||
private Listener<SourceEvent> mSourceEventListener;
|
|
||||||
private int mMeasuredFrequencyError;
|
private int mMeasuredFrequencyError;
|
||||||
|
private double mUsableBandwidthPercentage;
|
||||||
|
private SourceEventListenerToProcessorAdapter mSourceEventListener;
|
||||||
private NativeBufferWaveRecorder mRecorder;
|
private NativeBufferWaveRecorder mRecorder;
|
||||||
private ITunerErrorListener mTunerErrorListener;
|
private ITunerErrorListener mTunerErrorListener;
|
||||||
public FrequencyErrorCorrectionManager mFrequencyErrorCorrectionManager;
|
|
||||||
private DecimalFormat mFrequencyErrorPPMFormat = new DecimalFormat("0.0");
|
private DecimalFormat mFrequencyErrorPPMFormat = new DecimalFormat("0.0");
|
||||||
|
private FrequencyErrorCorrectionManager mFrequencyErrorCorrectionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels
|
* Abstract tuner controller class. The tuner controller manages frequency bandwidth and currently tuned channels
|
||||||
@@ -78,6 +78,15 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
return mFrequencyErrorCorrectionManager;
|
return mFrequencyErrorCorrectionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void dispose()
|
||||||
|
{
|
||||||
|
getFrequencyErrorCorrectionManager().dispose();
|
||||||
|
mNativeBufferBroadcaster.clear();
|
||||||
|
mFrequencyController.dispose();
|
||||||
|
mSourceEventListener.dispose();
|
||||||
|
mTunerErrorListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform startup operations
|
* Perform startup operations
|
||||||
* @throws SourceException if there is an error that makes this tuner controller unusable
|
* @throws SourceException if there is an error that makes this tuner controller unusable
|
||||||
@@ -141,7 +150,6 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor,
|
|||||||
setFrequency(config.getFrequency());
|
setFrequency(config.getFrequency());
|
||||||
setFrequencyCorrection(config.getFrequencyCorrection());
|
setFrequencyCorrection(config.getFrequencyCorrection());
|
||||||
getFrequencyErrorCorrectionManager().setEnabled(config.getAutoPPMCorrectionEnabled());
|
getFrequencyErrorCorrectionManager().setEnabled(config.getAutoPPMCorrectionEnabled());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ import io.github.dsheirer.source.SourceException;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class FrequencyController
|
public class FrequencyController
|
||||||
{
|
{
|
||||||
@@ -40,8 +41,8 @@ public class FrequencyController
|
|||||||
private double mFrequencyCorrection = 0.0d;
|
private double mFrequencyCorrection = 0.0d;
|
||||||
private double mSampleRate = 0.0d;
|
private double mSampleRate = 0.0d;
|
||||||
private boolean mLocked = false;
|
private boolean mLocked = false;
|
||||||
|
private List<ISourceEventProcessor> mProcessors = new ArrayList<>();
|
||||||
private List<ISourceEventProcessor> mProcessors = new CopyOnWriteArrayList<>();
|
private ReentrantLock mLock = new ReentrantLock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an instance
|
* Constructs an instance
|
||||||
@@ -52,6 +53,15 @@ public class FrequencyController
|
|||||||
mTunable = tunable;
|
mTunable = tunable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare for disposal of this instance.
|
||||||
|
*/
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
mProcessors.clear();
|
||||||
|
mTunable = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this frequency controller is locked by a remote process. A locked state indicates that neither
|
* 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
|
* the frequency nor the sample rate should be changed. The remote process will typically be a downstream
|
||||||
@@ -276,9 +286,18 @@ public class FrequencyController
|
|||||||
*/
|
*/
|
||||||
public void addListener(ISourceEventProcessor processor)
|
public void addListener(ISourceEventProcessor processor)
|
||||||
{
|
{
|
||||||
if(!mProcessors.contains(processor))
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
mProcessors.add(processor);
|
if(!mProcessors.contains(processor))
|
||||||
|
{
|
||||||
|
mProcessors.add(processor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +306,16 @@ public class FrequencyController
|
|||||||
*/
|
*/
|
||||||
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
|
public void removeFrequencyChangeProcessor(ISourceEventProcessor processor)
|
||||||
{
|
{
|
||||||
mProcessors.remove(processor);
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
mProcessors.remove(processor);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -318,9 +346,18 @@ public class FrequencyController
|
|||||||
|
|
||||||
public void broadcast(SourceEvent event) throws SourceException
|
public void broadcast(SourceEvent event) throws SourceException
|
||||||
{
|
{
|
||||||
for(ISourceEventProcessor processor : mProcessors)
|
mLock.lock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
processor.process(event);
|
for(ISourceEventProcessor processor : mProcessors)
|
||||||
|
{
|
||||||
|
processor.process(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
mLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ public abstract class ChannelSourceManager implements ISourceEventProcessor
|
|||||||
{
|
{
|
||||||
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
private Broadcaster<SourceEvent> mSourceEventBroadcaster = new Broadcaster<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare for disposal
|
||||||
|
*/
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
mSourceEventBroadcaster.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorted set of tuner channels being sourced by this source manager. Set is ordered by frequency lowest to highest
|
* Sorted set of tuner channels being sourced by this source manager. Set is ordered by frequency lowest to highest
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ public class FrequencyErrorCorrectionManager
|
|||||||
mTunerController = tunerController;
|
mTunerController = tunerController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose of this manager instance and nullify references.
|
||||||
|
*/
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
setEnabled(false);
|
||||||
|
mTunerController = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables automatic frequency PPM correction.
|
* Enables or disables automatic frequency PPM correction.
|
||||||
* @param enabled to true to turn on automatic PPM adjustments.
|
* @param enabled to true to turn on automatic PPM adjustments.
|
||||||
@@ -80,7 +89,7 @@ public class FrequencyErrorCorrectionManager
|
|||||||
*/
|
*/
|
||||||
private void applyCorrection()
|
private void applyCorrection()
|
||||||
{
|
{
|
||||||
if(mEnabled && mTunerController.hasMeasuredFrequencyError())
|
if(mEnabled && mTunerController != null && mTunerController.hasMeasuredFrequencyError())
|
||||||
{
|
{
|
||||||
double frequencyCorrection = mTunerController.getFrequencyCorrection();
|
double frequencyCorrection = mTunerController.getFrequencyCorrection();
|
||||||
frequencyCorrection -= mTunerController.getPPMFrequencyError();
|
frequencyCorrection -= mTunerController.getPPMFrequencyError();
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import io.github.dsheirer.source.tuner.TunerClass;
|
|||||||
import io.github.dsheirer.source.tuner.TunerFactory;
|
import io.github.dsheirer.source.tuner.TunerFactory;
|
||||||
import io.github.dsheirer.source.tuner.TunerType;
|
import io.github.dsheirer.source.tuner.TunerType;
|
||||||
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
import io.github.dsheirer.source.tuner.configuration.TunerConfiguration;
|
||||||
import io.github.dsheirer.source.tuner.manager.FrequencyErrorCorrectionManager;
|
|
||||||
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
import io.github.dsheirer.source.tuner.usb.USBTunerController;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -300,16 +299,6 @@ public class RTL2832TunerController extends USBTunerController
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Manager for applying automatic frequency error PPM adjustments to the tuner controller based on
|
|
||||||
* frequency error measurements received from certain downstream decoders (e.g. P25).
|
|
||||||
* @return manager
|
|
||||||
*/
|
|
||||||
public FrequencyErrorCorrectionManager getFrequencyErrorCorrectionManager()
|
|
||||||
{
|
|
||||||
return mFrequencyErrorCorrectionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides updates for measured frequency error so that the updates can also be applied to the
|
* Overrides updates for measured frequency error so that the updates can also be applied to the
|
||||||
* frequency error correction manager for automatic PPM updating.
|
* frequency error correction manager for automatic PPM updating.
|
||||||
@@ -348,11 +337,11 @@ public class RTL2832TunerController extends USBTunerController
|
|||||||
{
|
{
|
||||||
if(hasEmbeddedTuner())
|
if(hasEmbeddedTuner())
|
||||||
{
|
{
|
||||||
return TunerClass.RTL2832.toString() + "/" + getTunerType().getLabel() + " " + mDescriptor.getSerial();
|
return TunerClass.RTL2832 + "/" + getTunerType().getLabel() + " " + mDescriptor.getSerial();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return TunerClass.RTL2832.toString() + " " + mDescriptor.getSerial();
|
return TunerClass.RTL2832 + " " + mDescriptor.getSerial();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -99,6 +99,8 @@ public class DiscoveredTunerEditor extends Editor<DiscoveredTuner> implements ID
|
|||||||
|
|
||||||
super.setItem(tuner);
|
super.setItem(tuner);
|
||||||
|
|
||||||
|
mEditorScroller.remove(mEditor);
|
||||||
|
|
||||||
if(hasItem())
|
if(hasItem())
|
||||||
{
|
{
|
||||||
mEditor = TunerFactory.getEditor(mUserPreferences, getItem(), mTunerManager);
|
mEditor = TunerFactory.getEditor(mUserPreferences, getItem(), mTunerManager);
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**r
|
||||||
* Indicates if the controls are currently being loaded with values.
|
* Indicates if the controls are currently being loaded with values.
|
||||||
*/
|
*/
|
||||||
protected boolean isLoading()
|
protected boolean isLoading()
|
||||||
@@ -337,7 +337,7 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
|||||||
if(mEnabledButton == null)
|
if(mEnabledButton == null)
|
||||||
{
|
{
|
||||||
mEnabledButton = new JButton(BUTTON_STATUS_ENABLE);
|
mEnabledButton = new JButton(BUTTON_STATUS_ENABLE);
|
||||||
mEnabledButton.setToolTipText("Enable or disable the tuner for use by sdrtrunk, or attempt to reset a tuner error");
|
mEnabledButton.setToolTipText("Enable or disable the tuner for use by sdrtrunk");
|
||||||
mEnabledButton.addActionListener(e ->
|
mEnabledButton.addActionListener(e ->
|
||||||
{
|
{
|
||||||
switch(getEnabledButton().getText())
|
switch(getEnabledButton().getText())
|
||||||
@@ -493,6 +493,11 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
|||||||
*/
|
*/
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
|
turnOffRecorder();
|
||||||
|
|
||||||
|
getFrequencyControl().clearListeners();
|
||||||
|
getFrequencyCorrectionSpinner().removeChangeListener(mFrequencyAndCorrectionChangeListener);
|
||||||
|
|
||||||
if(mDiscoveredTuner != null)
|
if(mDiscoveredTuner != null)
|
||||||
{
|
{
|
||||||
mDiscoveredTuner.removeTunerStatusListener(this);
|
mDiscoveredTuner.removeTunerStatusListener(this);
|
||||||
@@ -501,9 +506,12 @@ public abstract class TunerEditor<T extends Tuner,C extends TunerConfiguration>
|
|||||||
{
|
{
|
||||||
mDiscoveredTuner.getTuner().removeTunerEventListener(this);
|
mDiscoveredTuner.getTuner().removeTunerEventListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDiscoveredTuner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
turnOffRecorder();
|
mUserPreferences = null;
|
||||||
|
mTunerManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user