diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java
index 30d482e2..564c1d68 100644
--- a/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java
+++ b/src/main/java/io/github/dsheirer/audio/broadcast/BroadcastModel.java
@@ -1,6 +1,7 @@
-/*******************************************************************************
+/*
+ * ******************************************************************************
* sdrtrunk
- * Copyright (C) 2014-2016 Dennis Sheirer
+ * 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
@@ -14,14 +15,15 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
- *
- ******************************************************************************/
+ * *****************************************************************************
+ */
package io.github.dsheirer.audio.broadcast;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.icon.IconManager;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
@@ -79,17 +81,15 @@ public class BroadcastModel extends AbstractTableModel implements Listener
- *
- ******************************************************************************/
+ * *****************************************************************************
+ */
package io.github.dsheirer.audio.broadcast;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.AudioRecorder;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableAudioPacket;
@@ -26,7 +28,6 @@ import io.github.dsheirer.util.TimeStamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
@@ -46,7 +47,7 @@ public class StreamManager implements Listener
private Listener mAudioRecordingListener;
private BroadcastFormat mBroadcastFormat;
- private Path mTempDirectory;
+ private UserPreferences mUserPreferences;
private Map mStreamRecorders = new HashMap<>();
private Runnable mRecorderMonitor;
private ScheduledFuture> mRecorderMonitorFuture;
@@ -61,15 +62,14 @@ public class StreamManager implements Listener
* Completed streamable audio recordings are nominated to the output listener (for broadcast) upon completion
*
* @param listener to receive completed audio recordings
- * @param tempDirectory where to store temporary audio recordings
+ * @param broadcastFormat for the stream
+ * @param userPreferences to obtain the temporary streaming recording directory
*/
- public StreamManager(Listener listener, BroadcastFormat broadcastFormat, Path tempDirectory)
+ public StreamManager(Listener listener, BroadcastFormat broadcastFormat, UserPreferences userPreferences)
{
- assert (tempDirectory != null && Files.isDirectory(tempDirectory));
-
mAudioRecordingListener = listener;
mBroadcastFormat = broadcastFormat;
- mTempDirectory = tempDirectory;
+ mUserPreferences = userPreferences;
}
/**
@@ -204,7 +204,7 @@ public class StreamManager implements Listener
sb.append(TimeStamp.getLongTimeStamp("_"));
sb.append(mBroadcastFormat.getFileExtension());
- Path temporaryRecordingPath = mTempDirectory.resolve(sb.toString());
+ Path temporaryRecordingPath = mUserPreferences.getDirectoryPreference().getDirectoryStreaming().resolve(sb.toString());
return temporaryRecordingPath;
}
diff --git a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java
index e418e570..a033697f 100644
--- a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java
+++ b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java
@@ -36,6 +36,7 @@ import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.preference.PreferenceEditorType;
import io.github.dsheirer.gui.preference.PreferenceEditorViewRequest;
import io.github.dsheirer.icon.IconManager;
+import io.github.dsheirer.log.ApplicationLog;
import io.github.dsheirer.map.MapService;
import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -56,7 +57,6 @@ import io.github.dsheirer.spectrum.SpectralDisplayPanel;
import io.github.dsheirer.util.ThreadPool;
import io.github.dsheirer.util.TimeStamp;
import net.miginfocom.swing.MigLayout;
-import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -89,6 +89,7 @@ import java.util.List;
public class SDRTrunk implements Listener
{
private final static Logger mLog = LoggerFactory.getLogger(SDRTrunk.class);
+
private static final String PROPERTY_BROADCAST_STATUS_VISIBLE = "main.broadcast.status.visible";
private boolean mBroadcastStatusVisible;
@@ -106,21 +107,14 @@ public class SDRTrunk implements Listener
private JideSplitPane mSplitPane;
private JavaFxWindowManager mJavaFxWindowManager;
private UserPreferences mUserPreferences = new UserPreferences();
+ private ApplicationLog mApplicationLog;
private String mTitle;
public SDRTrunk()
{
- mLog.info("*******************************************************************");
- mLog.info("**** sdrtrunk: a trunked radio and digital decoding application ***");
- mLog.info("**** website: https://github.com/dsheirer/sdrtrunk ***");
- mLog.info("*******************************************************************");
- mLog.info("Memory Logging Format: [Used/Allocated PercentUsed%]");
- mLog.info("Host OS Name: " + System.getProperty("os.name"));
- mLog.info("Host OS Arch: " + System.getProperty("os.arch"));
- mLog.info("Host OS Version: " + System.getProperty("os.version"));
- mLog.info("Host CPU Cores: " + Runtime.getRuntime().availableProcessors());
- mLog.info("Host Max Java Memory: " + FileUtils.byteCountToDisplaySize(Runtime.getRuntime().maxMemory()));
+ mApplicationLog = new ApplicationLog(mUserPreferences);
+ mApplicationLog.start();
//Setup the application home directory
Path home = getHomePath();
@@ -151,9 +145,9 @@ public class SDRTrunk implements Listener
ChannelMapModel channelMapModel = new ChannelMapModel();
- EventLogManager eventLogManager = new EventLogManager();
+ EventLogManager eventLogManager = new EventLogManager(mUserPreferences);
- RecorderManager recorderManager = new RecorderManager(aliasModel);
+ RecorderManager recorderManager = new RecorderManager(aliasModel, mUserPreferences);
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences);
@@ -170,7 +164,7 @@ public class SDRTrunk implements Listener
AudioPlaybackManager audioPlaybackManager = new AudioPlaybackManager(mSourceManager.getMixerManager());
- mBroadcastModel = new BroadcastModel(aliasModel, mIconManager);
+ mBroadcastModel = new BroadcastModel(aliasModel, mIconManager, mUserPreferences);
//Audio packets are routed through the audio packet manager for metadata enrichment and then
//distributed to the audio packet processors (ie playback, recording, streaming, etc.)
@@ -373,47 +367,20 @@ public class SDRTrunk implements Listener
{
Robot robot = new Robot();
- final BufferedImage image =
- robot.createScreenCapture(mMainGui.getBounds());
+ final BufferedImage image = robot.createScreenCapture(mMainGui.getBounds());
- SystemProperties props = SystemProperties.getInstance();
+ String filename = TimeStamp.getTimeStamp("_") + "_screen_capture.png";
- Path capturePath = props.getApplicationFolder("screen_captures");
+ final Path captureFile = mUserPreferences.getDirectoryPreference().getDirectoryScreenCapture().resolve(filename);
- if(!Files.exists(capturePath))
- {
+ EventQueue.invokeLater(() -> {
try
{
- Files.createDirectory(capturePath);
+ ImageIO.write(image, "png", captureFile.toFile());
}
catch(IOException e)
{
- mLog.error("Couldn't create 'screen_captures' "
- + "subdirectory in the " +
- "SDRTrunk application directory", e);
- }
- }
-
- String filename = TimeStamp.getTimeStamp("_") +
- "_screen_capture.png";
-
- final Path captureFile = capturePath.resolve(filename);
-
- EventQueue.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- try
- {
- ImageIO.write(image, "png",
- captureFile.toFile());
- }
- catch(IOException e)
- {
- mLog.error("Couldn't write screen capture to "
- + "file [" + captureFile.toString() + "]", e);
- }
+ mLog.error("Couldn't write screen capture to file [" + captureFile.toString() + "]", e);
}
});
}
@@ -442,6 +409,7 @@ public class SDRTrunk implements Listener
mLog.info("Releasing tuners ...");
mSourceManager.shutdown();
mLog.info("Shutdown complete.");
+ mApplicationLog.stop();
}
/**
diff --git a/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorFactory.java b/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorFactory.java
index ac8dd70b..1b149851 100644
--- a/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorFactory.java
+++ b/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorFactory.java
@@ -20,6 +20,7 @@
package io.github.dsheirer.gui.preference;
+import io.github.dsheirer.gui.preference.directory.DirectoryPreferenceEditor;
import io.github.dsheirer.gui.preference.tuner.TunerPreferenceEditor;
import io.github.dsheirer.preference.UserPreferences;
import javafx.scene.Node;
@@ -33,10 +34,12 @@ public class PreferenceEditorFactory
{
switch(preferenceEditorType)
{
- case TALKGROUP_FORMAT:
- return new TalkgroupFormatPreferenceEditor(userPreferences);
case CHANNEL_EVENT:
return new DecodeEventViewPreferenceEditor(userPreferences);
+ case DIRECTORY:
+ return new DirectoryPreferenceEditor(userPreferences);
+ case TALKGROUP_FORMAT:
+ return new TalkgroupFormatPreferenceEditor(userPreferences);
case TUNER:
return new TunerPreferenceEditor(userPreferences);
}
diff --git a/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorType.java b/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorType.java
index 940952a5..b076b7da 100644
--- a/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorType.java
+++ b/src/main/java/io/github/dsheirer/gui/preference/PreferenceEditorType.java
@@ -25,9 +25,10 @@ package io.github.dsheirer.gui.preference;
*/
public enum PreferenceEditorType
{
- CHANNEL_EVENT("Channel Event"),
- TALKGROUP_FORMAT("Talkgroup Display"),
- TUNER("Tuner");
+ CHANNEL_EVENT("Channel Events"),
+ DIRECTORY("Directories"),
+ TALKGROUP_FORMAT("Talkgroups"),
+ TUNER("Tuners");
private String mLabel;
diff --git a/src/main/java/io/github/dsheirer/gui/preference/PreferencesEditor.java b/src/main/java/io/github/dsheirer/gui/preference/PreferencesEditor.java
index 3f9018da..babc7061 100644
--- a/src/main/java/io/github/dsheirer/gui/preference/PreferencesEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/preference/PreferencesEditor.java
@@ -104,7 +104,7 @@ public class PreferencesEditor extends Application
public void start(Stage stage) throws Exception
{
stage.setTitle("Preferences");
- Scene scene = new Scene(getBorderPane(), 800, 500);
+ Scene scene = new Scene(getBorderPane(), 900, 500);
stage.setScene(scene);
stage.show();
}
@@ -192,10 +192,19 @@ public class PreferencesEditor extends Application
TreeItem displayItem = new TreeItem<>("Display");
displayItem.getChildren().add(new TreeItem(PreferenceEditorType.CHANNEL_EVENT));
displayItem.getChildren().add(new TreeItem(PreferenceEditorType.TALKGROUP_FORMAT));
- displayItem.getChildren().add(new TreeItem(PreferenceEditorType.TUNER));
treeRoot.getChildren().add(displayItem);
displayItem.setExpanded(true);
+ TreeItem storageItem = new TreeItem<>("File Storage");
+ storageItem.getChildren().add(new TreeItem(PreferenceEditorType.DIRECTORY));
+ treeRoot.getChildren().add(storageItem);
+ storageItem.setExpanded(true);
+
+ TreeItem sourceItem = new TreeItem<>("Source");
+ sourceItem.getChildren().add(new TreeItem(PreferenceEditorType.TUNER));
+ treeRoot.getChildren().add(sourceItem);
+ sourceItem.setExpanded(true);
+
mEditorSelectionTreeView = new TreeView();
mEditorSelectionTreeView.setShowRoot(false);
mEditorSelectionTreeView.setRoot(treeRoot);
diff --git a/src/main/java/io/github/dsheirer/gui/preference/directory/DirectoryPreferenceEditor.java b/src/main/java/io/github/dsheirer/gui/preference/directory/DirectoryPreferenceEditor.java
new file mode 100644
index 00000000..8c9794ec
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/gui/preference/directory/DirectoryPreferenceEditor.java
@@ -0,0 +1,684 @@
+/*
+ * ******************************************************************************
+ * sdrtrunk
+ * 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 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
+ * *****************************************************************************
+ */
+
+package io.github.dsheirer.gui.preference.directory;
+
+import com.google.common.eventbus.Subscribe;
+import io.github.dsheirer.eventbus.MyEventBus;
+import io.github.dsheirer.preference.PreferenceType;
+import io.github.dsheirer.preference.UserPreferences;
+import io.github.dsheirer.preference.directory.DirectoryPreference;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.geometry.Orientation;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.Separator;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.stage.DirectoryChooser;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+
+/**
+ * Preference settings for channel event view
+ */
+public class DirectoryPreferenceEditor extends HBox
+{
+ private final static Logger mLog = LoggerFactory.getLogger(DirectoryPreferenceEditor.class);
+
+ private DirectoryPreference mDirectoryPreference;
+ private GridPane mEditorPane;
+
+ private Label mApplicationRootLabel;
+ private Button mChangeApplicationRootButton;
+ private Button mResetApplicationRootButton;
+ private Label mApplicationRootPathLabel;
+
+ private Label mApplicationLogsLabel;
+ private Button mChangeApplicationLogsButton;
+ private Button mResetApplicationLogsButton;
+ private Label mApplicationLogsPathLabel;
+
+ private Label mEventLogsLabel;
+ private Button mChangeEventLogsButton;
+ private Button mResetEventLogsButton;
+ private Label mEventLogsPathLabel;
+
+ private Label mPlaylistLabel;
+ private Button mChangePlaylistButton;
+ private Button mResetPlaylistButton;
+ private Label mPlaylistPathLabel;
+
+ private Label mRecordingLabel;
+ private Button mChangeRecordingButton;
+ private Button mResetRecordingButton;
+ private Label mRecordingPathLabel;
+
+ private Label mScreenCaptureLabel;
+ private Button mChangeScreenCaptureButton;
+ private Button mResetScreenCaptureButton;
+ private Label mScreenCapturePathLabel;
+
+ private Label mStreamingLabel;
+ private Button mChangeStreamingButton;
+ private Button mResetStreamingButton;
+ private Label mStreamingPathLabel;
+
+ public DirectoryPreferenceEditor(UserPreferences userPreferences)
+ {
+ mDirectoryPreference = userPreferences.getDirectoryPreference();
+
+ //Register to receive directory preference update notifications so we can update the path labels
+ MyEventBus.getEventBus().register(this);
+
+ HBox.setHgrow(getEditorPane(), Priority.ALWAYS);
+ getChildren().add(getEditorPane());
+ }
+
+ private GridPane getEditorPane()
+ {
+ if(mEditorPane == null)
+ {
+ mEditorPane = new GridPane();
+ mEditorPane.setPadding(new Insets(10, 10, 10, 10));
+
+ int row = 0;
+
+ Label itemLabel = new Label("Item");
+ GridPane.setMargin(itemLabel, new Insets(0, 10, 0, 0));
+ mEditorPane.add(itemLabel, 0, row);
+
+ Label directoryLabel = new Label("Directory");
+ GridPane.setMargin(directoryLabel, new Insets(0, 10, 0, 0));
+ mEditorPane.add(directoryLabel, 1, row++);
+
+ mEditorPane.add(new Separator(Orientation.HORIZONTAL), 0, row++, 4, 1);
+
+ GridPane.setMargin(getApplicationRootLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getApplicationRootLabel(), 0, row);
+
+ GridPane.setMargin(getApplicationRootPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getApplicationRootPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeApplicationRootButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeApplicationRootButton(), 2, row);
+
+ GridPane.setMargin(getResetApplicationRootButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetApplicationRootButton(), 3, row++);
+
+
+ GridPane.setMargin(getApplicationLogsLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getApplicationLogsLabel(), 0, row);
+
+ GridPane.setMargin(getApplicationLogsPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getApplicationLogsPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeApplicationLogsButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeApplicationLogsButton(), 2, row);
+
+ GridPane.setMargin(getResetApplicationLogsButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetApplicationLogsButton(), 3, row++);
+
+
+ GridPane.setMargin(getEventLogsLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getEventLogsLabel(), 0, row);
+
+ GridPane.setMargin(getEventLogsPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getEventLogsPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeEventLogsButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeEventLogsButton(), 2, row);
+
+ GridPane.setMargin(getResetEventLogsButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetEventLogsButton(), 3, row++);
+
+
+ GridPane.setMargin(getPlaylistLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getPlaylistLabel(), 0, row);
+
+ GridPane.setMargin(getPlaylistPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getPlaylistPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangePlaylistButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangePlaylistButton(), 2, row);
+
+ GridPane.setMargin(getResetPlaylistButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetPlaylistButton(), 3, row++);
+
+
+ GridPane.setMargin(getRecordingLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getRecordingLabel(), 0, row);
+
+ GridPane.setMargin(getRecordingPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getRecordingPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeRecordingButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeRecordingButton(), 2, row);
+
+ GridPane.setMargin(getResetRecordingButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetRecordingButton(), 3, row++);
+
+
+ GridPane.setMargin(getScreenCaptureLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getScreenCaptureLabel(), 0, row);
+
+ GridPane.setMargin(getScreenCapturePathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getScreenCapturePathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeScreenCaptureButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeScreenCaptureButton(), 2, row);
+
+ GridPane.setMargin(getResetScreenCaptureButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetScreenCaptureButton(), 3, row++);
+
+
+ GridPane.setMargin(getStreamingLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getStreamingLabel(), 0, row);
+
+ GridPane.setMargin(getStreamingPathLabel(), new Insets(0, 10, 0, 0));
+ mEditorPane.add(getStreamingPathLabel(), 1, row);
+
+ GridPane.setMargin(getChangeStreamingButton(), new Insets(2, 10, 2, 0));
+ mEditorPane.add(getChangeStreamingButton(), 2, row);
+
+ GridPane.setMargin(getResetStreamingButton(), new Insets(2, 0, 2, 0));
+ mEditorPane.add(getResetStreamingButton(), 3, row++);
+ }
+
+ return mEditorPane;
+ }
+
+ private Label getApplicationRootLabel()
+ {
+ if(mApplicationRootLabel == null)
+ {
+ mApplicationRootLabel = new Label("Application Root");
+ }
+
+ return mApplicationRootLabel;
+ }
+
+ private Button getChangeApplicationRootButton()
+ {
+ if(mChangeApplicationRootButton == null)
+ {
+ mChangeApplicationRootButton = new Button("Change...");
+ mChangeApplicationRootButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Application Root Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryApplicationRoot().toFile());
+ Stage stage = (Stage)getChangeApplicationRootButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryApplicationRoot(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeApplicationRootButton;
+ }
+
+ private Button getResetApplicationRootButton()
+ {
+ if(mResetApplicationRootButton == null)
+ {
+ mResetApplicationRootButton = new Button("Reset");
+ mResetApplicationRootButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryApplicationRoot();
+ }
+ });
+ }
+
+ return mResetApplicationRootButton;
+ }
+
+ private Label getApplicationRootPathLabel()
+ {
+ if(mApplicationRootPathLabel == null)
+ {
+ mApplicationRootPathLabel = new Label(mDirectoryPreference.getDirectoryApplicationRoot().toString());
+ }
+
+ return mApplicationRootPathLabel;
+ }
+
+ private Label getApplicationLogsLabel()
+ {
+ if(mApplicationLogsLabel == null)
+ {
+ mApplicationLogsLabel = new Label("Application Logs");
+ }
+
+ return mApplicationLogsLabel;
+ }
+
+ private Button getChangeApplicationLogsButton()
+ {
+ if(mChangeApplicationLogsButton == null)
+ {
+ mChangeApplicationLogsButton = new Button("Change...");
+ mChangeApplicationLogsButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Application Logs Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryApplicationLog().toFile());
+ Stage stage = (Stage)getChangeApplicationLogsButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryApplicationLogs(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeApplicationLogsButton;
+ }
+
+ private Button getResetApplicationLogsButton()
+ {
+ if(mResetApplicationLogsButton == null)
+ {
+ mResetApplicationLogsButton = new Button("Reset");
+ mResetApplicationLogsButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryApplicationLogs();
+ }
+ });
+ }
+
+ return mResetApplicationLogsButton;
+ }
+
+ private Label getApplicationLogsPathLabel()
+ {
+ if(mApplicationLogsPathLabel == null)
+ {
+ mApplicationLogsPathLabel = new Label(mDirectoryPreference.getDirectoryApplicationLog().toString());
+ }
+
+ return mApplicationLogsPathLabel;
+ }
+
+ private Label getEventLogsLabel()
+ {
+ if(mEventLogsLabel == null)
+ {
+ mEventLogsLabel = new Label("Event Logs");
+ }
+
+ return mEventLogsLabel;
+ }
+
+ private Button getChangeEventLogsButton()
+ {
+ if(mChangeEventLogsButton == null)
+ {
+ mChangeEventLogsButton = new Button("Change...");
+ mChangeEventLogsButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Event Logs Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryEventLog().toFile());
+ Stage stage = (Stage)getChangeEventLogsButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryEventLogs(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeEventLogsButton;
+ }
+
+ private Button getResetEventLogsButton()
+ {
+ if(mResetEventLogsButton == null)
+ {
+ mResetEventLogsButton = new Button("Reset");
+ mResetEventLogsButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryEventLogs();
+ }
+ });
+ }
+
+ return mResetEventLogsButton;
+ }
+
+ private Label getEventLogsPathLabel()
+ {
+ if(mEventLogsPathLabel == null)
+ {
+ mEventLogsPathLabel = new Label(mDirectoryPreference.getDirectoryEventLog().toString());
+ }
+
+ return mEventLogsPathLabel;
+ }
+
+ private Label getPlaylistLabel()
+ {
+ if(mPlaylistLabel == null)
+ {
+ mPlaylistLabel = new Label("Playlists");
+ }
+
+ return mPlaylistLabel;
+ }
+
+ private Button getChangePlaylistButton()
+ {
+ if(mChangePlaylistButton == null)
+ {
+ mChangePlaylistButton = new Button("Change...");
+ mChangePlaylistButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Playlist Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryPlaylist().toFile());
+ Stage stage = (Stage)getChangePlaylistButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryPlaylist(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangePlaylistButton;
+ }
+
+ private Button getResetPlaylistButton()
+ {
+ if(mResetPlaylistButton == null)
+ {
+ mResetPlaylistButton = new Button("Reset");
+ mResetPlaylistButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryPlaylist();
+ }
+ });
+ }
+
+ return mResetPlaylistButton;
+ }
+
+ private Label getPlaylistPathLabel()
+ {
+ if(mPlaylistPathLabel == null)
+ {
+ mPlaylistPathLabel = new Label(mDirectoryPreference.getDirectoryPlaylist().toString());
+ }
+
+ return mPlaylistPathLabel;
+ }
+
+ private Label getRecordingLabel()
+ {
+ if(mRecordingLabel == null)
+ {
+ mRecordingLabel = new Label("Recordings");
+ }
+
+ return mRecordingLabel;
+ }
+
+ private Button getChangeRecordingButton()
+ {
+ if(mChangeRecordingButton == null)
+ {
+ mChangeRecordingButton = new Button("Change...");
+ mChangeRecordingButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Recording Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryRecording().toFile());
+ Stage stage = (Stage)getChangeRecordingButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryRecording(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeRecordingButton;
+ }
+
+ private Button getResetRecordingButton()
+ {
+ if(mResetRecordingButton == null)
+ {
+ mResetRecordingButton = new Button("Reset");
+ mResetRecordingButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryRecording();
+ }
+ });
+ }
+
+ return mResetRecordingButton;
+ }
+
+ private Label getRecordingPathLabel()
+ {
+ if(mRecordingPathLabel == null)
+ {
+ mRecordingPathLabel = new Label(mDirectoryPreference.getDirectoryRecording().toString());
+ }
+
+ return mRecordingPathLabel;
+ }
+
+ private Label getScreenCaptureLabel()
+ {
+ if(mScreenCaptureLabel == null)
+ {
+ mScreenCaptureLabel = new Label("Screen Captures");
+ }
+
+ return mScreenCaptureLabel;
+ }
+
+ private Button getChangeScreenCaptureButton()
+ {
+ if(mChangeScreenCaptureButton == null)
+ {
+ mChangeScreenCaptureButton = new Button("Change...");
+ mChangeScreenCaptureButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Screen Capture Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryScreenCapture().toFile());
+ Stage stage = (Stage)getChangeScreenCaptureButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryScreenCapture(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeScreenCaptureButton;
+ }
+
+ private Button getResetScreenCaptureButton()
+ {
+ if(mResetScreenCaptureButton == null)
+ {
+ mResetScreenCaptureButton = new Button("Reset");
+ mResetScreenCaptureButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryScreenCapture();
+ }
+ });
+ }
+
+ return mResetScreenCaptureButton;
+ }
+
+ private Label getScreenCapturePathLabel()
+ {
+ if(mScreenCapturePathLabel == null)
+ {
+ mScreenCapturePathLabel = new Label(mDirectoryPreference.getDirectoryScreenCapture().toString());
+ }
+
+ return mScreenCapturePathLabel;
+ }
+
+ private Label getStreamingLabel()
+ {
+ if(mStreamingLabel == null)
+ {
+ mStreamingLabel = new Label("Streaming");
+ }
+
+ return mStreamingLabel;
+ }
+
+ private Button getChangeStreamingButton()
+ {
+ if(mChangeStreamingButton == null)
+ {
+ mChangeStreamingButton = new Button("Change...");
+ mChangeStreamingButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ DirectoryChooser directoryChooser = new DirectoryChooser();
+ directoryChooser.setTitle("Select Streaming Folder");
+ directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryStreaming().toFile());
+ Stage stage = (Stage)getChangeStreamingButton().getScene().getWindow();
+ File selected = directoryChooser.showDialog(stage);
+
+ if(selected != null)
+ {
+ mDirectoryPreference.setDirectoryStreaming(selected.toPath());
+ }
+ }
+ });
+ }
+
+ return mChangeStreamingButton;
+ }
+
+ private Button getResetStreamingButton()
+ {
+ if(mResetStreamingButton == null)
+ {
+ mResetStreamingButton = new Button("Reset");
+ mResetStreamingButton.setOnAction(new EventHandler()
+ {
+ @Override
+ public void handle(ActionEvent event)
+ {
+ mDirectoryPreference.resetDirectoryStreaming();
+ }
+ });
+ }
+
+ return mResetStreamingButton;
+ }
+
+ private Label getStreamingPathLabel()
+ {
+ if(mStreamingPathLabel == null)
+ {
+ mStreamingPathLabel = new Label(mDirectoryPreference.getDirectoryStreaming().toString());
+ }
+
+ return mStreamingPathLabel;
+ }
+
+ @Subscribe
+ public void preferenceUpdated(PreferenceType preferenceType)
+ {
+ if(preferenceType != null && preferenceType == PreferenceType.DIRECTORY)
+ {
+ getApplicationRootPathLabel().setText(mDirectoryPreference.getDirectoryApplicationRoot().toString());
+ getApplicationLogsPathLabel().setText(mDirectoryPreference.getDirectoryApplicationLog().toString());
+ getEventLogsPathLabel().setText(mDirectoryPreference.getDirectoryEventLog().toString());
+ getPlaylistPathLabel().setText(mDirectoryPreference.getDirectoryPlaylist().toString());
+ getRecordingPathLabel().setText(mDirectoryPreference.getDirectoryRecording().toString());
+ getScreenCapturePathLabel().setText(mDirectoryPreference.getDirectoryScreenCapture().toString());
+ getStreamingPathLabel().setText(mDirectoryPreference.getDirectoryStreaming().toString());
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/gui/preference/tuner/TunerPreferenceEditor.java b/src/main/java/io/github/dsheirer/gui/preference/tuner/TunerPreferenceEditor.java
index 3b3c44c2..9e4a04e6 100644
--- a/src/main/java/io/github/dsheirer/gui/preference/tuner/TunerPreferenceEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/preference/tuner/TunerPreferenceEditor.java
@@ -68,6 +68,7 @@ public class TunerPreferenceEditor extends HBox
GridPane.setMargin(getChannelizerLabel(), new Insets(0, 10, 0, 0));
GridPane.setHalignment(getChannelizerLabel(), HPos.LEFT);
mEditorPane.add(getChannelizerLabel(), 0, 0);
+ GridPane.setMargin(getChannelizerTypeChoiceBox(), new Insets(2, 0, 2, 0));
mEditorPane.add(getChannelizerTypeChoiceBox(), 1, 0);
mEditorPane.add(new Separator(Orientation.HORIZONTAL), 0, 1, 2, 1);
mEditorPane.add(getPolyphaseLabel(), 0, 2, 2, 1);
diff --git a/src/main/java/io/github/dsheirer/log/ApplicationLog.java b/src/main/java/io/github/dsheirer/log/ApplicationLog.java
new file mode 100644
index 00000000..a4b8bbaf
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/log/ApplicationLog.java
@@ -0,0 +1,166 @@
+/*
+ * ******************************************************************************
+ * sdrtrunk
+ * 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 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
+ * *****************************************************************************
+ */
+
+package io.github.dsheirer.log;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.filter.ThresholdFilter;
+import ch.qos.logback.core.rolling.RollingFileAppender;
+import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
+import com.google.common.eventbus.Subscribe;
+import io.github.dsheirer.eventbus.MyEventBus;
+import io.github.dsheirer.preference.PreferenceType;
+import io.github.dsheirer.preference.UserPreferences;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.file.Path;
+
+/**
+ * Logback and SLF4j logging implementation.
+ */
+public class ApplicationLog
+{
+ private final static Logger mLog = LoggerFactory.getLogger(ApplicationLog.class);
+
+ private static final String APPLICATION_LOG_FILENAME = "sdrtrunk_app.log";
+ private static final int APPLICATION_LOG_MAX_HISTORY = 10;
+
+ private UserPreferences mUserPreferences;
+ private RollingFileAppender mRollingFileAppender;
+ private Path mApplicationLogPath;
+
+ /**
+ * Constructs the application log instance. Note: use the start() method to initiate logging.
+ * @param userPreferences
+ */
+ public ApplicationLog(UserPreferences userPreferences)
+ {
+ mUserPreferences = userPreferences;
+ MyEventBus.getEventBus().register(this);
+ }
+
+ @Subscribe
+ public void preferenceUpdated(PreferenceType preferenceType)
+ {
+ if(preferenceType == PreferenceType.DIRECTORY && mRollingFileAppender != null && mApplicationLogPath != null)
+ {
+ Path applicationLogPath = mUserPreferences.getDirectoryPreference().getDirectoryApplicationLog();
+
+ //Restart the application log if the path is updated
+ if(!applicationLogPath.equals(mApplicationLogPath))
+ {
+ mLog.info("Application logging directory has changed [" + applicationLogPath.toString() + " ] - restarting logging");
+ stop();
+ start();
+ }
+ }
+ }
+
+ /**
+ * Starts application logging
+ */
+ public void start()
+ {
+ if(mRollingFileAppender == null)
+ {
+ mApplicationLogPath = mUserPreferences.getDirectoryPreference().getDirectoryApplicationLog();
+ Path logfile = mApplicationLogPath.resolve(APPLICATION_LOG_FILENAME);
+ mLog.info("Application Log File: " + logfile.toString());
+
+ LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
+
+ PatternLayoutEncoder encoder = new PatternLayoutEncoder();
+ encoder.setContext(loggerContext);
+ encoder.setPattern("%-25(%d{yyyyMMdd HHmmss.SSS} [%thread]) %-5level %logger{30} - %msg %memory_usage%n");
+ encoder.start();
+
+ mRollingFileAppender = new RollingFileAppender();
+ mRollingFileAppender.setContext(loggerContext);
+ mRollingFileAppender.setAppend(true);
+ mRollingFileAppender.setName("FILE");
+ mRollingFileAppender.setEncoder(encoder);
+ mRollingFileAppender.setFile(logfile.toString());
+
+ ThresholdFilter thresholdFilter = new ThresholdFilter();
+ thresholdFilter.setLevel(Level.DEBUG.toString());
+ thresholdFilter.setContext(loggerContext);
+ thresholdFilter.setName("sdrtrunk threshold filter");
+ thresholdFilter.start();
+
+ mRollingFileAppender.addFilter(thresholdFilter);
+
+ String pattern = logfile.toString().replace(APPLICATION_LOG_FILENAME, "%d{yyyyMMdd}_" + APPLICATION_LOG_FILENAME);
+ TimeBasedRollingPolicy rollingPolicy = new TimeBasedRollingPolicy<>();
+ rollingPolicy.setContext(loggerContext);
+ rollingPolicy.setFileNamePattern(pattern);
+ rollingPolicy.setMaxHistory(APPLICATION_LOG_MAX_HISTORY);
+ rollingPolicy.setParent(mRollingFileAppender);
+ rollingPolicy.start();
+
+ mRollingFileAppender.setRollingPolicy(rollingPolicy);
+ mRollingFileAppender.start();
+
+ Logger logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
+ ((ch.qos.logback.classic.Logger)logger).setLevel(Level.ALL);
+ ((ch.qos.logback.classic.Logger)logger).addAppender(mRollingFileAppender);
+
+// StatusPrinter.print(loggerContext);
+
+ mLog.info("");
+ mLog.info("*******************************************************************");
+ mLog.info("**** sdrtrunk: a trunked radio and digital decoding application ***");
+ mLog.info("**** website: https://github.com/dsheirer/sdrtrunk ***");
+ mLog.info("*******************************************************************");
+ mLog.info("Memory Logging Format: [Used/Allocated PercentUsed%]");
+ mLog.info("Host OS Name: " + System.getProperty("os.name"));
+ mLog.info("Host OS Arch: " + System.getProperty("os.arch"));
+ mLog.info("Host OS Version: " + System.getProperty("os.version"));
+ mLog.info("Host CPU Cores: " + Runtime.getRuntime().availableProcessors());
+ mLog.info("Host Max Java Memory: " + FileUtils.byteCountToDisplaySize(Runtime.getRuntime().maxMemory()));
+ mLog.info("Storage Directories:");
+ mLog.info(" Application Root: " + mUserPreferences.getDirectoryPreference().getDirectoryApplicationRoot());
+ mLog.info(" Application Log: " + mUserPreferences.getDirectoryPreference().getDirectoryApplicationLog());
+ mLog.info(" Event Log: " + mUserPreferences.getDirectoryPreference().getDirectoryEventLog());
+ mLog.info(" Playlist: " + mUserPreferences.getDirectoryPreference().getDirectoryPlaylist());
+ mLog.info(" Recordings: " + mUserPreferences.getDirectoryPreference().getDirectoryRecording());
+ }
+
+ }
+
+ /**
+ * Stops the log file appender and nullifies it for shutdown or for reinitialization.
+ */
+ public void stop()
+ {
+ if(mRollingFileAppender != null)
+ {
+ mLog.info("Stopping application logging");
+ mRollingFileAppender.stop();
+ LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
+ Logger logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
+ ((ch.qos.logback.classic.Logger)logger).detachAppender(mRollingFileAppender);
+ mRollingFileAppender = null;
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java
index 057b7374..798e0d5d 100644
--- a/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java
+++ b/src/main/java/io/github/dsheirer/module/decode/event/DecodeEventPanel.java
@@ -26,6 +26,7 @@ import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.channel.IChannelDescriptor;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.icon.IconManager;
+import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.Role;
@@ -202,7 +203,15 @@ public class DecodeEventPanel extends JPanel implements Listener, IDataUnitDetectListen
}
catch(BitSetFullException bsfe)
{
- mLog.debug("Message full exception - unexpected");
+// mLog.debug("Message full exception - unexpected");
//Reset so that we can start over again
reset(0);
@@ -280,9 +280,9 @@ public class P25MessageFramer2 implements Listener, IDataUnitDetectListen
mTrailingDibitsToSuppress = 22;
break;
default:
- mLog.debug("*** MORE THAN 5 PDU BLOCKS DETECTED [" +
- mPDUSequence.getHeader().getBlocksToFollowCount() +
- "] - DETERMINE TRAILING NULL COUNT TO SUPPRESS AND UPDATE CODE");
+// mLog.debug("*** MORE THAN 5 PDU BLOCKS DETECTED [" +
+// mPDUSequence.getHeader().getBlocksToFollowCount() +
+// "] - DETERMINE TRAILING NULL COUNT TO SUPPRESS AND UPDATE CODE");
break;
}
@@ -298,7 +298,7 @@ public class P25MessageFramer2 implements Listener, IDataUnitDetectListen
}
else
{
- mLog.error("Received PDU data block with out a preceeding data header");
+// mLog.error("Received PDU data block with out a preceeding data header");
reset(mDataUnitID.getMessageLength());
}
break;
@@ -489,39 +489,6 @@ public class P25MessageFramer2 implements Listener, IDataUnitDetectListen
}
});
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180922_040600_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180922_042033_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_045614_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits"); //Has Moto LC Opcode 01
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_045647_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_050325_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_050403_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_050721_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_051057_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits"); //ARS PDUs and SNDCP PDUs
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_051808_9600BPS_CNYICC_Onondaga Simulcast_LCN 09_EMERG_AND_PACKETS.bits"); //ARS and SNCDP PDUs
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20180923_052519_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181008_091511_9600BPS_CNYICC_Onondaga Simulcast_LCN 15 Control.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181008_091650_9600BPS_CNYICC_Onondaga Simulcast_LCN 15 Control.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_101745_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_101850_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_101855_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_102145_9600BPS_CNYICC_Onondaga Simulcast_LCN 04.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_102451_9600BPS_CNYICC_Onondaga Simulcast_LCN 09_lots_of_PACKET_DATA.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_102456_9600BPS_CNYICC_Onondaga Simulcast_LCN 10.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_102459_9600BPS_CNYICC_Onondaga Simulcast_LCN 11.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_102501_9600BPS_CNYICC_Onondaga Simulcast_LCN 12.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181021_103208_9600BPS_CNYICC_Onondaga Simulcast_LCN 09.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_140834_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_140851_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_141547_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_141607_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_142300_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_142319_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_143012_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_143031_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_143723_9600BPS_CNYICC_Onondaga Simulcast_LCN 06.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181028_143741_9600BPS_CNYICC_Onondaga Simulcast_LCN 07.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181102_100905_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits");
-// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181102_101622_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits");
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181102_102339_9600BPS_CNYICC_Onondaga Simulcast_LCN 08.bits");
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_134948_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits");
// Path path = Paths.get("/home/denny/SDRTrunk/recordings/20181103_144312_9600BPS_CNYICC_Oswego Simulcast_LCN 04.bits"); //Interesting UDP port 231 packets (oswego LCN 4)
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java
index a7bdbb6e..bc08f3fe 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java
@@ -286,6 +286,7 @@ public class P25TrafficChannelManager extends Module implements IDecodeEventProv
break;
case OSP_SNDCP_DATA_CHANNEL_GRANT:
+ case OSP_GROUP_DATA_CHANNEL_GRANT:
case OSP_INDIVIDUAL_DATA_CHANNEL_GRANT:
type = encrypted ? DecodeEventType.DATA_CALL_ENCRYPTED : DecodeEventType.DATA_CALL;
break;
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java
index b00bbf5d..ff50b033 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/message/P25Message.java
@@ -1,6 +1,7 @@
-/*******************************************************************************
+/*
+ * ******************************************************************************
* sdrtrunk
- * Copyright (C) 2014-2017 Dennis Sheirer
+ * 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
@@ -14,8 +15,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
- *
- ******************************************************************************/
+ * *****************************************************************************
+ */
package io.github.dsheirer.module.decode.p25.message;
import io.github.dsheirer.bits.CorrectedBinaryMessage;
@@ -88,7 +89,7 @@ public abstract class P25Message extends Message
/**
* The transmitted binary message
*/
- protected CorrectedBinaryMessage getMessage()
+ public CorrectedBinaryMessage getMessage()
{
return mMessage;
}
diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java
index 959536c1..cd446fd0 100644
--- a/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java
+++ b/src/main/java/io/github/dsheirer/module/decode/p25/message/tsbk/Opcode.java
@@ -1,3 +1,23 @@
+/*
+ * ******************************************************************************
+ * sdrtrunk
+ * 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 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
+ * *****************************************************************************
+ */
+
package io.github.dsheirer.module.decode.p25.message.tsbk;
import io.github.dsheirer.module.decode.p25.reference.Direction;
@@ -150,6 +170,7 @@ public enum Opcode
MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT(2, "PTCH GRP VCHN GR", "MOTOROLA PATCH GROUP CHANNEL GRANT"),
MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT_UPDATE(3, "PTCH GRP VCH UPD", "MOTOROLA PATCH GROUP CHANNEL GRANT UPDATE"),
MOTOROLA_OSP_TRAFFIC_CHANNEL_ID(5, "CHANNEL CWID", "CHANNEL CWID"),
+ MOTOROLA_OSP_OPCODE_7(7, "MOTOROLA OPCODE 7", "MOTOROLA OPCODE 07"),
MOTOROLA_OSP_SYSTEM_LOADING(9, "SYSTEM LOADING", "SYSTEM LOADING"),
MOTOROLA_OSP_CONTROL_CHANNEL_ID(11, "CCH BASE STAT ID", "CONTROL CHANNEL BASE STATION ID"),
MOTOROLA_OSP_CONTROL_CHANNEL_PLANNED_SHUTDOWN(14, "CCH PLND SHUTDWN", "CONTROL CHANNEL PLANNED SHUTDOWN"),
@@ -272,6 +293,8 @@ public enum Opcode
return MOTOROLA_OSP_PATCH_GROUP_CHANNEL_GRANT_UPDATE;
case 0x05:
return MOTOROLA_OSP_TRAFFIC_CHANNEL_ID;
+ case 0x07:
+ return MOTOROLA_OSP_OPCODE_7;
case 0x09:
return MOTOROLA_OSP_SYSTEM_LOADING;
case 0x0B:
diff --git a/src/main/java/io/github/dsheirer/module/log/EventLogManager.java b/src/main/java/io/github/dsheirer/module/log/EventLogManager.java
index b552d4eb..5eaf099d 100644
--- a/src/main/java/io/github/dsheirer/module/log/EventLogManager.java
+++ b/src/main/java/io/github/dsheirer/module/log/EventLogManager.java
@@ -22,7 +22,7 @@ package io.github.dsheirer.module.log;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.module.log.config.EventLogConfiguration;
-import io.github.dsheirer.properties.SystemProperties;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.util.StringUtils;
import org.slf4j.Logger;
@@ -36,12 +36,11 @@ public class EventLogManager
{
private final static Logger mLog = LoggerFactory.getLogger(EventLogManager.class);
- private Path mDirectory;
+ private UserPreferences mUserPreferences;
- public EventLogManager()
+ public EventLogManager(UserPreferences userPreferences)
{
- mDirectory = SystemProperties.getInstance()
- .getApplicationFolder("event_logs");
+ mUserPreferences = userPreferences;
}
public List getLoggers(Channel channel)
@@ -89,16 +88,18 @@ public class EventLogManager
sb.append(eventLogType.getFileSuffix());
sb.append(".log");
+ Path eventLogDirectory = mUserPreferences.getDirectoryPreference().getDirectoryEventLog();
+
switch(eventLogType)
{
case CALL_EVENT:
- return new DecodeEventLogger(mDirectory, sb.toString(), frequency);
+ return new DecodeEventLogger(eventLogDirectory, sb.toString(), frequency);
case DECODED_MESSAGE:
- return new MessageEventLogger(mDirectory, sb.toString(), MessageEventLogger.Type.DECODED, frequency);
+ return new MessageEventLogger(eventLogDirectory, sb.toString(), MessageEventLogger.Type.DECODED, frequency);
case TRAFFIC_CALL_EVENT:
- return new DecodeEventLogger(mDirectory, sb.toString(), frequency);
+ return new DecodeEventLogger(eventLogDirectory, sb.toString(), frequency);
case TRAFFIC_DECODED_MESSAGE:
- return new MessageEventLogger(mDirectory, sb.toString(), MessageEventLogger.Type.DECODED, frequency);
+ return new MessageEventLogger(eventLogDirectory, sb.toString(), MessageEventLogger.Type.DECODED, frequency);
default:
return null;
}
diff --git a/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java b/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
index 3ee2267a..05755b9a 100644
--- a/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
+++ b/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
@@ -33,7 +33,7 @@ import io.github.dsheirer.controller.channel.ChannelModel;
import io.github.dsheirer.controller.channel.map.ChannelMapEvent;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.preference.UserPreferences;
-import io.github.dsheirer.preference.playlist.FilePreferences;
+import io.github.dsheirer.preference.playlist.PlaylistPreference;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
@@ -186,7 +186,7 @@ public class PlaylistManager implements Listener
*/
private void save()
{
- FilePreferences files = mUserPreferences.getFilePreferences();
+ PlaylistPreference files = mUserPreferences.getPlaylistPreference();
PlaylistV2 playlist = new PlaylistV2();
@@ -239,7 +239,7 @@ public class PlaylistManager implements Listener
Files.delete(files.getPlaylistLock());
}
- mUserPreferences.getFilePreferences().setPlaylistLastAccessedPath(files.getPlaylist());
+ mUserPreferences.getPlaylistPreference().setPlaylistLastAccessedPath(files.getPlaylist());
}
catch(IOException ioe)
{
@@ -256,7 +256,7 @@ public class PlaylistManager implements Listener
*/
public PlaylistV2 load()
{
- FilePreferences files = mUserPreferences.getFilePreferences();
+ PlaylistPreference files = mUserPreferences.getPlaylistPreference();
PlaylistV2 playlist = null;
diff --git a/src/main/java/io/github/dsheirer/preference/PreferenceType.java b/src/main/java/io/github/dsheirer/preference/PreferenceType.java
index 81e4fa16..5f00a600 100644
--- a/src/main/java/io/github/dsheirer/preference/PreferenceType.java
+++ b/src/main/java/io/github/dsheirer/preference/PreferenceType.java
@@ -26,7 +26,7 @@ package io.github.dsheirer.preference;
public enum PreferenceType
{
DECODE_EVENT,
- FILES,
+ DIRECTORY,
IDENTIFIER,
TUNER;
}
diff --git a/src/main/java/io/github/dsheirer/preference/UserPreferences.java b/src/main/java/io/github/dsheirer/preference/UserPreferences.java
index 181c66cd..bef3682a 100644
--- a/src/main/java/io/github/dsheirer/preference/UserPreferences.java
+++ b/src/main/java/io/github/dsheirer/preference/UserPreferences.java
@@ -21,19 +21,34 @@
package io.github.dsheirer.preference;
import io.github.dsheirer.eventbus.MyEventBus;
+import io.github.dsheirer.preference.directory.DirectoryPreference;
import io.github.dsheirer.preference.event.DecodeEventPreference;
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
-import io.github.dsheirer.preference.playlist.FilePreferences;
+import io.github.dsheirer.preference.playlist.PlaylistPreference;
import io.github.dsheirer.preference.tuner.TunerPreference;
import io.github.dsheirer.sample.Listener;
/**
* User Preferences. A collection of preferences that can be accessed by preference type.
+ *
+ * Note: user preference updates are broadcast throughout the system using the Google Guava Event Bus. Each component
+ * can register with the event bus and annotate a method to receive updates:
+ *
+ * To register a component to receive events, add this in the constructor:
+ * MyEventBus.getEventBus().register(this);
+ *
+ * To receive preference update notifications, annotate a method with @Subscribe and use a PreferenceType argument:
+ *
+ * @Subscribe
+ * public void preferenceUpdated(PreferenceType preferenceType)
+ * {
+ * }
*/
public class UserPreferences implements Listener
{
private DecodeEventPreference mDecodeEventPreference;
- private FilePreferences mFilePreferences;
+ private DirectoryPreference mDirectoryPreference;
+ private PlaylistPreference mPlaylistPreference;
private TalkgroupFormatPreference mTalkgroupFormatPreference;
private TunerPreference mTunerPreference;
@@ -53,12 +68,20 @@ public class UserPreferences implements Listener
return mDecodeEventPreference;
}
+ /**
+ * Directory preferences
+ */
+ public DirectoryPreference getDirectoryPreference()
+ {
+ return mDirectoryPreference;
+ }
+
/**
* Playlist preferences
*/
- public FilePreferences getFilePreferences()
+ public PlaylistPreference getPlaylistPreference()
{
- return mFilePreferences;
+ return mPlaylistPreference;
}
/**
@@ -83,7 +106,8 @@ public class UserPreferences implements Listener
private void loadPreferenceTypes()
{
mDecodeEventPreference = new DecodeEventPreference(this);
- mFilePreferences = new FilePreferences(this::receive);
+ mDirectoryPreference = new DirectoryPreference(this::receive);
+ mPlaylistPreference = new PlaylistPreference(this, mDirectoryPreference);
mTalkgroupFormatPreference = new TalkgroupFormatPreference(this);
mTunerPreference = new TunerPreference(this);
}
diff --git a/src/main/java/io/github/dsheirer/preference/directory/DirectoryPreference.java b/src/main/java/io/github/dsheirer/preference/directory/DirectoryPreference.java
new file mode 100644
index 00000000..77d829fa
--- /dev/null
+++ b/src/main/java/io/github/dsheirer/preference/directory/DirectoryPreference.java
@@ -0,0 +1,444 @@
+/*
+ * ******************************************************************************
+ * sdrtrunk
+ * 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 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
+ * *****************************************************************************
+ */
+
+package io.github.dsheirer.preference.directory;
+
+import io.github.dsheirer.preference.Preference;
+import io.github.dsheirer.preference.PreferenceType;
+import io.github.dsheirer.sample.Listener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.prefs.Preferences;
+
+/**
+ * User preferences for directories
+ */
+public class DirectoryPreference extends Preference
+{
+ private final static Logger mLog = LoggerFactory.getLogger(DirectoryPreference.class);
+ private Preferences mPreferences = Preferences.userNodeForPackage(DirectoryPreference.class);
+
+ private static final String DIRECTORY_APPLICATION_ROOT = "SDRTrunk";
+ private static final String DIRECTORY_APPLICATION_LOG = "logs";
+ private static final String DIRECTORY_EVENT_LOG = "event_logs";
+ private static final String DIRECTORY_PLAYLIST = "playlist";
+ private static final String DIRECTORY_RECORDING = "recordings";
+ private static final String DIRECTORY_SCREEN_CAPTURE = "screen_captures";
+ private static final String DIRECTORY_STREAMING = "streaming";
+
+ private static final String PREFERENCE_KEY_DIRECTORY_APPLICATION_ROOT = "directory.application.root";
+ private static final String PREFERENCE_KEY_DIRECTORY_APPLICATION_LOGS = "directory.application.logs";
+ private static final String PREFERENCE_KEY_DIRECTORY_EVENT_LOGS = "directory.event.logs";
+ private static final String PREFERENCE_KEY_DIRECTORY_PLAYLIST = "directory.playlist";
+ private static final String PREFERENCE_KEY_DIRECTORY_RECORDING = "directory.recording";
+ private static final String PREFERENCE_KEY_DIRECTORY_SCREEN_CAPTURE = "directory.screen.capture";
+ private static final String PREFERENCE_KEY_DIRECTORY_STREAMING = "directory.streaming";
+
+ private Path mDirectoryApplicationRoot;
+ private Path mDirectoryApplicationLogs;
+ private Path mDirectoryEventLogs;
+ private Path mDirectoryPlaylist;
+ private Path mDirectoryRecording;
+ private Path mDirectoryScreenCapture;
+ private Path mDirectoryStreaming;
+
+ /**
+ * Constructs this preference with an update listener
+ * @param updateListener to receive notifications whenever these preferences change
+ */
+ public DirectoryPreference(Listener updateListener)
+ {
+ super(updateListener);
+ }
+
+ @Override
+ public PreferenceType getPreferenceType()
+ {
+ return PreferenceType.DIRECTORY;
+ }
+
+ /**
+ * Path to the application root directory
+ */
+ public Path getDirectoryApplicationRoot()
+ {
+ if(mDirectoryApplicationRoot == null)
+ {
+ mDirectoryApplicationRoot = getPath(PREFERENCE_KEY_DIRECTORY_APPLICATION_ROOT, getDefaultApplicationDirectory());
+ createDirectory(mDirectoryApplicationRoot);
+ }
+
+ return mDirectoryApplicationRoot;
+ }
+
+ /**
+ * Sets the path to the application root directory
+ */
+ public void setDirectoryApplicationRoot(Path path)
+ {
+ mDirectoryApplicationRoot = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_APPLICATION_ROOT, path.toString());
+
+ //Set the child paths to null so that they'll be recreated on next access. If the user has explicitly set a
+ //path override for any of these directories, then it will be retained.
+ nullifyApplicationChildDirectories();
+
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Nullifies each of the application root child directories so that they can be re-created from application root
+ * or re-created from a persisted override path.
+ */
+ private void nullifyApplicationChildDirectories()
+ {
+ mDirectoryApplicationLogs = null;
+ mDirectoryEventLogs = null;
+ mDirectoryPlaylist = null;
+ mDirectoryRecording = null;
+ mDirectoryScreenCapture = null;
+ mDirectoryStreaming = null;
+ }
+
+ /**
+ * Removes a stored recording directory preference so that the default path can be used again
+ */
+ public void resetDirectoryApplicationRoot()
+ {
+ mDirectoryApplicationRoot = null;
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_APPLICATION_ROOT);
+
+ //Set the child paths to null so that they'll be recreated on next access. If the user has explicitly set a
+ //path override for any of these directories, then it will be retained.
+ nullifyApplicationChildDirectories();
+
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing application logs
+ */
+ public Path getDirectoryApplicationLog()
+ {
+ if(mDirectoryApplicationLogs == null)
+ {
+ mDirectoryApplicationLogs = getPath(PREFERENCE_KEY_DIRECTORY_APPLICATION_LOGS, getDefaultApplicationLogsDirectory());
+ createDirectory(mDirectoryApplicationLogs);
+ }
+
+ return mDirectoryApplicationLogs;
+ }
+
+ /**
+ * Sets the path to the application logs folder
+ */
+ public void setDirectoryApplicationLogs(Path path)
+ {
+ mDirectoryApplicationLogs = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_APPLICATION_LOGS, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored application logs directory preference so that the default path can be used again
+ */
+ public void resetDirectoryApplicationLogs()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_APPLICATION_LOGS);
+ mDirectoryApplicationLogs = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing event logs
+ */
+ public Path getDirectoryEventLog()
+ {
+ if(mDirectoryEventLogs == null)
+ {
+ mDirectoryEventLogs = getPath(PREFERENCE_KEY_DIRECTORY_EVENT_LOGS, getDefaultEventLogsDirectory());
+ createDirectory(mDirectoryEventLogs);
+ }
+
+ return mDirectoryEventLogs;
+ }
+
+ /**
+ * Sets the path to the event logs folder
+ */
+ public void setDirectoryEventLogs(Path path)
+ {
+ mDirectoryEventLogs = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_EVENT_LOGS, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored playlist directory preference so that the default path can be used again
+ */
+ public void resetDirectoryEventLogs()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_EVENT_LOGS);
+ mDirectoryEventLogs = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing playlist
+ */
+ public Path getDirectoryPlaylist()
+ {
+ if(mDirectoryPlaylist == null)
+ {
+ mDirectoryPlaylist = getPath(PREFERENCE_KEY_DIRECTORY_PLAYLIST, getDefaultPlaylistDirectory());
+ createDirectory(mDirectoryPlaylist);
+ }
+
+ return mDirectoryPlaylist;
+ }
+
+ /**
+ * Sets the path to the playlist folder
+ */
+ public void setDirectoryPlaylist(Path path)
+ {
+ mDirectoryPlaylist = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_PLAYLIST, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored playlist directory preference so that the default path can be used again
+ */
+ public void resetDirectoryPlaylist()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_PLAYLIST);
+ mDirectoryPlaylist = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing recordings
+ */
+ public Path getDirectoryRecording()
+ {
+ if(mDirectoryRecording == null)
+ {
+ mDirectoryRecording = getPath(PREFERENCE_KEY_DIRECTORY_RECORDING, getDefaultRecordingDirectory());
+ createDirectory(mDirectoryRecording);
+ }
+
+ return mDirectoryRecording;
+ }
+
+ /**
+ * Sets the path to the playlist folder
+ */
+ public void setDirectoryRecording(Path path)
+ {
+ mDirectoryRecording = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_RECORDING, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored recording directory preference so that the default path can be used again
+ */
+ public void resetDirectoryRecording()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_RECORDING);
+ mDirectoryRecording = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing screen capture
+ */
+ public Path getDirectoryScreenCapture()
+ {
+ if(mDirectoryScreenCapture == null)
+ {
+ mDirectoryScreenCapture = getPath(PREFERENCE_KEY_DIRECTORY_SCREEN_CAPTURE, getDefaultScreenCaptureDirectory());
+ createDirectory(mDirectoryScreenCapture);
+ }
+
+ return mDirectoryScreenCapture;
+ }
+
+ /**
+ * Sets the path to the screen capture folder
+ */
+ public void setDirectoryScreenCapture(Path path)
+ {
+ mDirectoryScreenCapture = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_SCREEN_CAPTURE, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored screen capture directory preference so that the default path can be used again
+ */
+ public void resetDirectoryScreenCapture()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_SCREEN_CAPTURE);
+ mDirectoryScreenCapture = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Path to the folder for storing streaming temporary recordings
+ */
+ public Path getDirectoryStreaming()
+ {
+ if(mDirectoryStreaming == null)
+ {
+ mDirectoryStreaming = getPath(PREFERENCE_KEY_DIRECTORY_STREAMING, getDefaultStreamingDirectory());
+ createDirectory(mDirectoryStreaming);
+ }
+
+ return mDirectoryStreaming;
+ }
+
+ /**
+ * Sets the path to the streaming folder
+ */
+ public void setDirectoryStreaming(Path path)
+ {
+ mDirectoryStreaming = path;
+ mPreferences.put(PREFERENCE_KEY_DIRECTORY_STREAMING, path.toString());
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Removes a stored streaming directory preference so that the default path can be used again
+ */
+ public void resetDirectoryStreaming()
+ {
+ mPreferences.remove(PREFERENCE_KEY_DIRECTORY_STREAMING);
+ mDirectoryStreaming = null;
+ notifyPreferenceUpdated();
+ }
+
+ /**
+ * Default application root directory
+ */
+ private Path getDefaultApplicationDirectory()
+ {
+ return Paths.get(System.getProperty("user.home"), DIRECTORY_APPLICATION_ROOT);
+ }
+
+ /**
+ * Default event logs directory
+ */
+ public Path getDefaultApplicationLogsDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_APPLICATION_LOG);
+ }
+
+ /**
+ * Default event logs directory
+ */
+ public Path getDefaultEventLogsDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_EVENT_LOG);
+ }
+
+ /**
+ * Default playlist directory
+ */
+ public Path getDefaultPlaylistDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_PLAYLIST);
+ }
+
+ /**
+ * Default playlist directory
+ */
+ public Path getDefaultRecordingDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_RECORDING);
+ }
+
+ /**
+ * Default screen capture directory
+ */
+ public Path getDefaultScreenCaptureDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_SCREEN_CAPTURE);
+ }
+
+ /**
+ * Default streaming directory
+ */
+ public Path getDefaultStreamingDirectory()
+ {
+ return getDirectoryApplicationRoot().resolve(DIRECTORY_STREAMING);
+ }
+
+ /**
+ * Returns the path stored in preferences and referenced by the key argument if it exists, otherwise returns the
+ * default path.
+ *
+ * Note: the default path is not checked for existence.
+ *
+ * @param key to the preferences service for the path
+ * @param defaultPath to use if the preferred path does not exist
+ * @return requested path
+ */
+ private Path getPath(String key, Path defaultPath)
+ {
+ String stringPath = mPreferences.get(key, defaultPath.toString());
+
+ if(stringPath != null && !stringPath.isEmpty())
+ {
+ Path temp = Paths.get(stringPath);
+
+ if(Files.exists(temp))
+ {
+ return temp;
+ }
+ }
+
+ return defaultPath;
+ }
+
+ /**
+ * Creates a directory if it does not already exist
+ */
+ private void createDirectory(Path directory)
+ {
+ if(!Files.exists(directory))
+ {
+ try
+ {
+ Files.createDirectory(directory);
+ mLog.info("Created directory [" + directory.toString() + "]");
+ }
+ catch(Exception e)
+ {
+ mLog.error("Error creating directory [" + directory.toString() + "]");
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/dsheirer/preference/playlist/FilePreferences.java b/src/main/java/io/github/dsheirer/preference/playlist/PlaylistPreference.java
similarity index 71%
rename from src/main/java/io/github/dsheirer/preference/playlist/FilePreferences.java
rename to src/main/java/io/github/dsheirer/preference/playlist/PlaylistPreference.java
index b5e715db..25319e28 100644
--- a/src/main/java/io/github/dsheirer/preference/playlist/FilePreferences.java
+++ b/src/main/java/io/github/dsheirer/preference/playlist/PlaylistPreference.java
@@ -22,6 +22,7 @@ package io.github.dsheirer.preference.playlist;
import io.github.dsheirer.preference.Preference;
import io.github.dsheirer.preference.PreferenceType;
+import io.github.dsheirer.preference.directory.DirectoryPreference;
import io.github.dsheirer.sample.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,39 +35,37 @@ import java.util.prefs.Preferences;
/**
* User preferences for playlists
*/
-public class FilePreferences extends Preference
+public class PlaylistPreference extends Preference
{
- private final static Logger mLog = LoggerFactory.getLogger(FilePreferences.class);
- private Preferences mPreferences = Preferences.userNodeForPackage(FilePreferences.class);
+ private final static Logger mLog = LoggerFactory.getLogger(PlaylistPreference.class);
+ private Preferences mPreferences = Preferences.userNodeForPackage(PlaylistPreference.class);
- private static final String FOLDER_APPLICATION_ROOT = "SDRTrunk";
- private static final String FOLDER_PLAYLIST = "playlist";
private static final String FILE_PLAYLIST = "default.xml";
private static final String FILE_LEGACY_PLAYLIST = "playlist_v2.xml";
- private static final String PREFERENCE_KEY_PLAYLIST_FOLDER = "playlist.folder";
private static final String PREFERENCE_KEY_PLAYLIST_LAST_ACCESSED = "playlist.last.accessed";
private static final String PREFERENCE_KEY_PLAYLIST_STARTUP = "playlist.default";
private static final String PREFERENCE_KEY_PLAYLIST_USE_LAST_ACCESSED = "playlist.use.last.accessed";
-
private Path mPlaylistFolder;
private Path mPlaylistStartupPath;
private Path mPlaylistLastAccessedPath;
private Boolean mUsePlaylistLastAccessedByDefault = true;
+ private DirectoryPreference mDirectoryPreference;
/**
* Constructs this preference with an update listener
* @param updateListener to receive notifications whenever these preferences change
*/
- public FilePreferences(Listener updateListener)
+ public PlaylistPreference(Listener updateListener, DirectoryPreference directoryPreference)
{
super(updateListener);
+ mDirectoryPreference = directoryPreference;
}
@Override
public PreferenceType getPreferenceType()
{
- return PreferenceType.FILES;
+ return PreferenceType.DIRECTORY;
}
@@ -90,7 +89,7 @@ public class FilePreferences extends Preference
*/
public Path getLegacyPlaylist()
{
- return getPlaylistFolder().resolve(FILE_LEGACY_PLAYLIST);
+ return mDirectoryPreference.getDirectoryPlaylist().resolve(FILE_LEGACY_PLAYLIST);
}
/**
@@ -157,29 +156,6 @@ public class FilePreferences extends Preference
notifyPreferenceUpdated();
}
- /**
- * Path to the folder for storing playlist
- */
- public Path getPlaylistFolder()
- {
- if(mPlaylistFolder == null)
- {
- mPlaylistFolder = getPath(PREFERENCE_KEY_PLAYLIST_FOLDER, getDefaultPlaylistFolder());
- }
-
- return mPlaylistFolder;
- }
-
- /**
- * Sets the path to the playlist folder
- */
- public void setPlaylistFolder(Path path)
- {
- mPlaylistFolder = path;
- mPreferences.put(PREFERENCE_KEY_PLAYLIST_FOLDER, path.toString());
- notifyPreferenceUpdated();
- }
-
/**
* Indicates the playlist to load on startup, either the last accessed playlist (true) or the default playlist (false).
*/
@@ -204,32 +180,12 @@ public class FilePreferences extends Preference
}
- /**
- * Default application root path
- */
- private Path getDefaultApplicationFolder()
- {
- Path defaultApplicationPath = Paths.get(System.getProperty("user.home"), FOLDER_APPLICATION_ROOT);
- createDirectory(defaultApplicationPath);
- return defaultApplicationPath;
- }
-
- /**
- * Default playlist folder
- */
- public Path getDefaultPlaylistFolder()
- {
- Path defaultPlaylistFolder = getDefaultApplicationFolder().resolve(FOLDER_PLAYLIST);
- createDirectory(defaultPlaylistFolder);
- return defaultPlaylistFolder;
- }
-
/**
* Default playlist
*/
private Path getDefaultPlaylistPath()
{
- return getDefaultPlaylistFolder().resolve(FILE_PLAYLIST);
+ return mDirectoryPreference.getDefaultPlaylistDirectory().resolve(FILE_PLAYLIST);
}
/**
@@ -244,7 +200,7 @@ public class FilePreferences extends Preference
*/
private Path getPath(String key, Path defaultPath)
{
- String stringPath = mPreferences.get(PREFERENCE_KEY_PLAYLIST_STARTUP, defaultPath.toString());
+ String stringPath = mPreferences.get(key, defaultPath.toString());
if(stringPath != null && !stringPath.isEmpty())
{
@@ -257,23 +213,4 @@ public class FilePreferences extends Preference
return defaultPath;
}
-
- /**
- * Creates a directory if it does not already exist
- */
- private void createDirectory(Path directory)
- {
- if(!Files.exists(directory) && Files.isDirectory(directory))
- {
- try
- {
- Files.createDirectory(directory);
- mLog.info("Created directory [" + directory.toString() + "]");
- }
- catch(Exception e)
- {
- mLog.error("Error creating directory [" + directory.toString() + "]");
- }
- }
- }
}
diff --git a/src/main/java/io/github/dsheirer/record/RecorderManager.java b/src/main/java/io/github/dsheirer/record/RecorderManager.java
index 59655c61..4a398a09 100644
--- a/src/main/java/io/github/dsheirer/record/RecorderManager.java
+++ b/src/main/java/io/github/dsheirer/record/RecorderManager.java
@@ -1,18 +1,22 @@
-/*******************************************************************************
- * sdr-trunk
+/*
+ * ******************************************************************************
+ * sdrtrunk
* 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.record;
import io.github.dsheirer.alias.AliasList;
@@ -24,7 +28,7 @@ import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.identifier.integer.IntegerIdentifier;
import io.github.dsheirer.identifier.string.StringIdentifier;
-import io.github.dsheirer.properties.SystemProperties;
+import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.wave.AudioPacketWaveRecorder;
import io.github.dsheirer.record.wave.ComplexBufferWaveRecorder;
import io.github.dsheirer.record.wave.WaveMetadata;
@@ -60,6 +64,7 @@ public class RecorderManager implements Listener
private List mAudioPackets = new ArrayList<>();
private ScheduledFuture> mBufferProcessorFuture;
private AliasModel mAliasModel;
+ private UserPreferences mUserPreferences;
private int mUnknownAudioRecordingIndex = 1;
private boolean mCanStartNewRecorders = true;
@@ -71,9 +76,10 @@ public class RecorderManager implements Listener
* indicating that the call is complete. A separate recording monitor periodically checks for idled recorders to
* be stopped for cases when the channel fails to send an end-call audio packet.
*/
- public RecorderManager(AliasModel aliasModel)
+ public RecorderManager(AliasModel aliasModel, UserPreferences userPreferences)
{
mAliasModel = aliasModel;
+ mUserPreferences = userPreferences;
mAudioPacketQueue.setOverflowListener(new IOverflowListener()
{
@Override
@@ -299,10 +305,13 @@ public class RecorderManager implements Listener
return getRecordingBasePath().resolve(sbFinal.toString());
}
-
+ /**
+ * Base path to recordings folder
+ * @return
+ */
public Path getRecordingBasePath()
{
- return SystemProperties.getInstance().getApplicationFolder("recordings");
+ return mUserPreferences.getDirectoryPreference().getDirectoryRecording();
}
/**
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 34f5140f..e3a78a8d 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -1,6 +1,7 @@
-
+ ~ ******************************************************************************
+ -->
-
- ${user.home}/SDRTrunk/logs/sdrtrunk_app.log
-
-
- ${user.home}/SDRTrunk/logs/%d{yyyyMMdd}_sdrtrunk_app.log
- 10
-
-
- %-25(%d{yyyyMMdd HHmmss.SSS} [%thread]) %-5level %logger{30} - %msg %memory_usage%n
-
-
-
-
-
-
-
%-12(%d{HH:mm:ss.SSS}) %-5level %logger{25} - %msg %memory_usage%n