From 20a8f2bb3c0eae18921e192ebd6716c2cdc36dce Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 14 Jul 2018 14:44:03 -0400 Subject: [PATCH] Fully implements application shutdown procedure that is invoked when the user closes the the main gui window or invokes exit from the file menu. --- .../channel/ChannelProcessingManager.java | 16 ++++++ .../java/io/github/dsheirer/gui/SDRTrunk.java | 57 ++++++++++++++----- .../github/dsheirer/source/SourceManager.java | 9 +++ .../github/dsheirer/source/tuner/Tuner.java | 4 ++ .../source/tuner/TunerController.java | 5 ++ .../dsheirer/source/tuner/TunerManager.java | 47 ++++++++++----- .../tuner/airspy/AirspyTunerController.java | 18 ++++++ .../source/tuner/hackrf/HackRFTuner.java | 4 -- .../tuner/hackrf/HackRFTunerController.java | 19 +++++++ .../source/tuner/rtl/RTL2832Tuner.java | 4 -- .../tuner/rtl/e4k/E4KTunerController.java | 20 +++++++ .../tuner/rtl/r820t/R820TTunerController.java | 21 +++++++ .../tuner/test/TestTunerController.java | 6 ++ 13 files changed, 195 insertions(+), 35 deletions(-) diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java index ae386a43..7ef918d3 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java @@ -363,6 +363,22 @@ public class ChannelProcessingManager implements ChannelEventListener } } + /** + * Stops all currently processing channels to prepare for shutdown. + */ + public void shutdown() + { + mLog.debug("Stopping Channels ..."); + for(Channel channel: mChannelModel.getChannels()) + { + if(channel.isProcessing()) + { + mLog.debug("Stopping channel: " + channel.toString()); + stopProcessing(channel, true); + } + } + } + /** * Adds a message listener that will be added to all channels to receive * any messages. diff --git a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java index b6d6b6d8..fc658253 100644 --- a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java +++ b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java @@ -69,6 +69,8 @@ import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.nio.file.FileSystems; @@ -88,6 +90,7 @@ public class SDRTrunk implements Listener private ControllerPanel mControllerPanel; private ChannelModel mChannelModel; private ChannelProcessingManager mChannelProcessingManager; + private SourceManager mSourceManager; private SettingsManager mSettingsManager; private SpectralDisplayPanel mSpectralPanel; private JFrame mMainGui = new JFrame(); @@ -141,10 +144,10 @@ public class SDRTrunk implements Listener RecorderManager recorderManager = new RecorderManager(); - SourceManager sourceManager = new SourceManager(tunerModel, mSettingsManager); + mSourceManager = new SourceManager(tunerModel, mSettingsManager); mChannelProcessingManager = new ChannelProcessingManager(mChannelModel, channelMapModel, aliasModel, - eventLogManager, recorderManager, sourceManager); + eventLogManager, recorderManager, mSourceManager); mChannelProcessingManager.addAudioPacketListener(recorderManager); mChannelModel.addListener(mChannelProcessingManager); @@ -156,7 +159,7 @@ public class SDRTrunk implements Listener AliasActionManager aliasActionManager = new AliasActionManager(); mChannelProcessingManager.addMessageListener(aliasActionManager); - AudioManager audioManager = new AudioManager(sourceManager.getMixerManager()); + AudioManager audioManager = new AudioManager(mSourceManager.getMixerManager()); mChannelProcessingManager.addAudioPacketListener(audioManager); mBroadcastModel = new BroadcastModel(mIconManager); @@ -168,13 +171,13 @@ public class SDRTrunk implements Listener mControllerPanel = new ControllerPanel(audioManager, aliasModel, mBroadcastModel, mChannelModel, channelMapModel, mChannelProcessingManager, mIconManager, - mapService, mSettingsManager, sourceManager, tunerModel); + mapService, mSettingsManager, mSourceManager, tunerModel); mSpectralPanel = new SpectralDisplayPanel(mChannelModel, mChannelProcessingManager, mSettingsManager); TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel, - mChannelModel, mChannelProcessingManager, mSettingsManager); + mChannelModel, mChannelProcessingManager, mSettingsManager); tunerModel.addListener(tunerSpectralDisplayManager); tunerModel.addListener(this); @@ -223,14 +226,6 @@ public class SDRTrunk implements Listener } } - /** - * Launch the application. - */ - public static void main(String[] args) - { - new SDRTrunk(); - } - /** * Initialize the contents of the frame. */ @@ -243,9 +238,10 @@ public class SDRTrunk implements Listener */ mTitle = SystemProperties.getInstance().getApplicationName(); mMainGui.setTitle(mTitle); - mMainGui.setSize(new Dimension(1280,800)); + mMainGui.setSize(new Dimension(1280, 800)); mMainGui.setLocationRelativeTo(null); mMainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + mMainGui.addWindowListener(new ShutdownMonitor()); //Set preferred sizes to influence the split mSpectralPanel.setPreferredSize(new Dimension(1280, 300)); @@ -318,6 +314,7 @@ public class SDRTrunk implements Listener { public void actionPerformed(ActionEvent event) { + processShutdown(); System.exit(0); } } @@ -400,6 +397,21 @@ public class SDRTrunk implements Listener menuBar.add(screenCaptureItem); } + /** + * Performs shutdown operations + */ + private void processShutdown() + { + mLog.debug("Application shutdown started ..."); + mLog.debug("Stopping channels ..."); + mChannelProcessingManager.shutdown(); + mLog.debug("Stopping spectral display ..."); + mSpectralPanel.clearTuner(); + mLog.debug("Releasing tuners ..."); + mSourceManager.shutdown(); + mLog.debug("Shutdown complete."); + } + /** * Lazy constructor for broadcast status panel */ @@ -520,6 +532,15 @@ public class SDRTrunk implements Listener } } + public class ShutdownMonitor extends WindowAdapter + { + @Override + public void windowClosing(WindowEvent e) + { + processShutdown(); + } + } + public class BroadcastStatusVisibleMenuItem extends JCheckBoxMenuItem { private ControllerPanel mControllerPanel; @@ -543,4 +564,12 @@ public class SDRTrunk implements Listener }); } } + + /** + * Launch the application. + */ + public static void main(String[] args) + { + new SDRTrunk(); + } } diff --git a/src/main/java/io/github/dsheirer/source/SourceManager.java b/src/main/java/io/github/dsheirer/source/SourceManager.java index 4af01bfd..5d652b0b 100644 --- a/src/main/java/io/github/dsheirer/source/SourceManager.java +++ b/src/main/java/io/github/dsheirer/source/SourceManager.java @@ -44,6 +44,15 @@ public class SourceManager //in via the constructor. Perform loading outside of this class. } + /** + * Prepare for shutdown and release all tuners + */ + public void shutdown() + { + mTunerManager.releaseTuners(); + mTunerManager.dispose(); + } + public MixerManager getMixerManager() { return mMixerManager; diff --git a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java index 915290b1..d74f52a8 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/Tuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/Tuner.java @@ -98,8 +98,12 @@ public abstract class Tuner implements ISourceEventProcessor return mName; } + /** + * Dispose and prepare for shutdown + */ public void dispose() { + getTunerController().dispose(); } /** 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 e533a6ad..88b65f68 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerController.java @@ -61,6 +61,11 @@ public abstract class TunerController implements Tunable, ISourceEventProcessor, mSourceEventListener = new SourceEventListenerToProcessorAdapter(this); } + /** + * Dispose of this tuner controller and prepare for shutdown. + */ + public abstract void dispose(); + /** * Implements the ISourceEventListener interface to receive requests from sample consumers */ diff --git a/src/main/java/io/github/dsheirer/source/tuner/TunerManager.java b/src/main/java/io/github/dsheirer/source/tuner/TunerManager.java index 91aae7ba..6261f44a 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/TunerManager.java +++ b/src/main/java/io/github/dsheirer/source/tuner/TunerManager.java @@ -1,19 +1,16 @@ /******************************************************************************* - * sdrtrunk - * Copyright (C) 2014-2017 Dennis Sheirer + * 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 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. + * 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 + * You should have received a copy of the GNU General Public License along with this program. + * If not, see * ******************************************************************************/ package io.github.dsheirer.source.tuner; @@ -74,7 +71,15 @@ public class TunerManager */ public void dispose() { - LibUsb.exit(null); + mLog.info("Shutting down LibUsb ..."); + try + { + LibUsb.exit(null); + } + catch(Exception e) + { + mLog.error("Error shutting down LibUsb", e); + } } /** @@ -217,6 +222,22 @@ public class TunerManager return new TunerInitStatus(null, "Unknown Device"); } + /** + * Releases all tuners in preparation for shutdown + */ + public void releaseTuners() + { + mLog.info("Releasing [" + mTunerModel.getTuners().size() + "] tuner(s) ..."); + Tuner tuner = mTunerModel.getTuner(0); + + while(tuner != null) + { + mTunerModel.removeTuner(tuner); + tuner.dispose(); + tuner = mTunerModel.getTuner(0); + } + } + private TunerInitStatus initAirspyTuner(Device device, DeviceDescriptor descriptor) { diff --git a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java index f7a9d022..20bc3060 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/airspy/AirspyTunerController.java @@ -180,6 +180,24 @@ public class AirspyTunerController extends USBTunerController USB_TRANSFER_BUFFER_SIZE); } + @Override + public void dispose() + { + if(mDeviceHandle != null) + { + mLog.info("Releasing Airspy Tuner - " + getDeviceInfo().getSerialNumber()); + try + { + LibUsb.close(mDeviceHandle); + } + catch(Exception e) + { + mLog.error("error while closing device handle", e); + } + + mDeviceHandle = null; + } + } @Override protected USBTransferProcessor getUSBTransferProcessor() diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTuner.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTuner.java index 2e1516fe..b655bde6 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTuner.java @@ -37,10 +37,6 @@ public class HackRFTuner extends Tuner return (HackRFTunerController)getTunerController(); } - public void dispose() - { - } - @Override public TunerClass getTunerClass() { diff --git a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java index e9082ec7..71e5c653 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/hackrf/HackRFTunerController.java @@ -157,6 +157,25 @@ public class HackRFTunerController extends USBTunerController mUSBTransferProcessor = new USBTransferProcessor(name, mDeviceHandle, mNativeBufferConverter, USB_TRANSFER_BUFFER_SIZE); } + @Override + public void dispose() + { + if(mDeviceHandle != null) + { + mLog.info("Releasing HackRF Tuner"); + try + { + LibUsb.close(mDeviceHandle); + } + catch(Exception e) + { + mLog.error("error while closing device handle", e); + } + + mDeviceHandle = null; + } + } + @Override protected USBTransferProcessor getUSBTransferProcessor() { diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832Tuner.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832Tuner.java index 4f84f4e8..d34f35c7 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832Tuner.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/RTL2832Tuner.java @@ -38,10 +38,6 @@ public class RTL2832Tuner extends Tuner mTunerClass = tunerClass; } - public void dispose() - { - } - public RTL2832TunerController getController() { return (RTL2832TunerController)getTunerController(); diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java index dcc0c24b..15436911 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/e4k/E4KTunerController.java @@ -256,6 +256,26 @@ public class E4KTunerController extends RTL2832TunerController USB_TRANSFER_BUFFER_SIZE); } + @Override + public void dispose() + { + if(mDeviceHandle != null) + { + mLog.info("Releasing E4000 Tuner"); + + try + { + LibUsb.close(mDeviceHandle); + } + catch(Exception e) + { + mLog.error("error while closing device handle", e); + } + + mDeviceHandle = null; + } + } + /** * Sets the IF filters (mixer, channel and RC) to the correct filter setting * for the selected bandwidth/sample rate diff --git a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java index c440ba04..6c9c802b 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/rtl/r820t/R820TTunerController.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.usb4java.Device; import org.usb4java.DeviceDescriptor; +import org.usb4java.LibUsb; import org.usb4java.LibUsbException; import javax.swing.JPanel; @@ -260,6 +261,26 @@ public class R820TTunerController extends RTL2832TunerController } } + @Override + public void dispose() + { + mLog.info("Releasing R820T Tuner"); + + if(mDeviceHandle != null) + { + try + { + LibUsb.close(mDeviceHandle); + } + catch(Exception e) + { + mLog.error("error while closing device handle", e); + } + + mDeviceHandle = null; + } + } + /** * Initializes the tuner section. */ diff --git a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java index 37c6a1c0..c2c8540f 100644 --- a/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java +++ b/src/main/java/io/github/dsheirer/source/tuner/test/TestTunerController.java @@ -65,6 +65,12 @@ public class TestTunerController extends TunerController } } + @Override + public void dispose() + { + //no-op + } + @Override public void addBufferListener(Listener listener) {