Compare commits

...

20 Commits

Author SHA1 Message Date
Dennis Sheirer
925353d515 Bump Version 0.5.0 Beta 3, Gradle 7.4.2, Embedded JDK 18.0.1 2022-05-04 14:51:27 -04:00
Denny Sheirer
7c32897321 #1229 Resolves issue with correctly identifying the port number for USB tuners that is causing some tuners not to be recognized and also generating udev errors when sdrtrunk attempts to start an already started device because it was incorrectly identified. (#1230)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-05-03 04:03:18 -04:00
Doug Hoffman
cbeda19d27 Generate audio metadata with correct to/from (#1215)
#1215 Generate audio metadata with correct to/from, preferring patch group, then talkgroup then other, for TO talkgroups.
2022-05-01 06:06:31 -04:00
Doug Hoffman
8148ca48af Normalize audio before recording (#1213)
#1213 Normalize audio before recording
2022-05-01 05:57:32 -04:00
VolFFProCoder
adcb55ffbc Add filter button to messages (#1098)
Adds filtering to channel decoded events panel.
2022-04-30 05:44:57 -04:00
Andrzej Pańkowski
1152b13220 Merge pull request #1177
* Fixes message filtering that was not being initialized.  Fixes minor spotted code issues
2022-04-30 04:25:33 -04:00
Doug Hoffman
166383e1ed Make Broadcastify Calls scheduled test configurable (#1218)
* Broadcastify Calls periodic keep-alive to avoid showing offline status
2022-04-30 04:04:10 -04:00
Denny Sheirer
0d5d1b20e3 #1223 Resolves NPE when Airspy and HackRF tuners are re-enabled after startup. Slight tweaks to TunerManager to change when discovered USB device startup takes place to potentially address intermittent fail on start for some tuners that users are seeing. Resolves issue where a started device was not unreferenced in LibUsb on shutdown. (#1224)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-29 08:00:18 -04:00
Denny Sheirer
77ea43f61a #1221 resolves null pointer exception in tuner editor when attempting to restart an error tuner. (#1222)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-28 04:40:52 -04:00
Denny Sheirer
f988344222 #1219 resolves issues with NPE and restarting an error tuner. (#1220)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-26 04:02:36 -04:00
Doug Hoffman
60489e1fef (icecast) Add support for inline metadata (#1212) 2022-04-25 04:38:54 -04:00
Doug Hoffman
ac8aa17a80 Check in with Broadcastify Calls to stay online while otherwise idle (#1214) 2022-04-24 05:15:34 -04:00
Denny Sheirer
25a42126df #1210 Resolves issue of tuner instances can't be garbage collected due to retained references. Updates several of the tuner controller and tuner editor classes to add/invoke dispose() methods to clear retained instance references. (#1216)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-24 04:56:10 -04:00
Denny Sheirer
1b90e0b50c #1209 updates tuner manager to properly deref usb devices on discovery. Updates tuner editors to separate enable/disable from tuner error state. Updates settings manager to disable auto-fail when loading xml file when unknown tags are encountered so that users' existing configs don't fail on startup and erase their existing settings. (#1211)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-04-23 06:05:12 -04:00
Denny Sheirer
7f5ad7eb20 Update README.md 2022-04-19 07:03:19 -04:00
Denny Sheirer
0e6713b6e2 Update README.md 2022-04-19 07:02:32 -04:00
Denny Sheirer
96d3996bec #1190 Tuner management redesign. Updates all tuners with direct threaded support. Incorporates USB Hotplug support. Adds black/white listing of tuners. Updates all tuner editors to have a common look and feel. Changes location of tuner configuration file and changes format to JSON. (#1208)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-04-18 07:30:58 -04:00
Denny Sheirer
0fb148d31e #1194 Resolves issue with audio stream bit rate scheduling that was causing stream disconnects for data rate under flows. (#1195)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-26 05:48:08 -04:00
Denny Sheirer
cebca28b19 Patch from @ImagoTrigger to implement headless operation: 9e4d2adfa9..c597d1967b (#1191)
Co-authored-by: Dennis Sheirer <dsheirer@github.com>
2022-03-25 04:19:38 -04:00
Denny Sheirer
af8cc0255e #1186 removes error logging that indicates that a channel cannot be stopped because it doesn't exist. This happens when a second successive attempt to stop a channel fails to find the channel because the first attempt has already removed the channel from the list. (#1187)
Co-authored-by: Denny Sheirer <sheirerd@ainfosec.com>
2022-03-21 19:09:49 -04:00
308 changed files with 13680 additions and 13207 deletions

View File

@@ -28,7 +28,7 @@ repositories {
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
} }
version = '0.5.0-beta2' version = '0.5.0-beta3'
sourceCompatibility = '17' sourceCompatibility = '17'
sourceSets { sourceSets {
@@ -58,7 +58,7 @@ dependencies {
//mavenCentral/jcenter imports //mavenCentral/jcenter imports
implementation 'ch.qos.logback:logback-classic:1.2.3' implementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'ch.qos.logback:logback-core:1.2.3' implementation 'ch.qos.logback:logback-core:1.2.3'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.2'
implementation 'com.fazecast:jSerialComm:2.5.0' implementation 'com.fazecast:jSerialComm:2.5.0'
implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1' implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1'
implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0' implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0'
@@ -139,11 +139,11 @@ String targetWindowsX86_64 = 'windows-x86_64-v' + version
* author's development environment, but can be changed to your environment if you want to use this build pattern. * author's development environment, but can be changed to your environment if you want to use this build pattern.
*/ */
String jdk_base = '/home/denny/java_jdks/' String jdk_base = '/home/denny/java_jdks/'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-17.0.2-full' String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-18.0.1-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-17.0.2-full' String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-18.0.1-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-17.0.2-full.jdk' String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-18.0.1-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-17.0.2-full.jdk' String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-18.0.1-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-17.0.2-full' String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-18.0.1-full'
boolean hasTargetJdks = file(jdk_linux_x86_64).exists() || file(jdk_linux_aarch64).exists() || boolean hasTargetJdks = file(jdk_linux_x86_64).exists() || file(jdk_linux_aarch64).exists() ||
file(jdk_osx_x86_64).exists() || file(jdk_osx_aarch64).exists() || file(jdk_windows_x86_64).exists() file(jdk_osx_x86_64).exists() || file(jdk_osx_aarch64).exists() || file(jdk_windows_x86_64).exists()
@@ -172,19 +172,19 @@ runtime {
println("Building all runtime images") println("Building all runtime images")
println("The [ > jre: ] build phase downloads several target JDKs and this may take a while ... please wait") println("The [ > jre: ] build phase downloads several target JDKs and this may take a while ... please wait")
targetPlatform(targetLinuxAarch64) { targetPlatform(targetLinuxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-linux-aarch64-full.tar.gz") jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-linux-aarch64-full.tar.gz")
} }
targetPlatform(targetLinuxX86_64) { targetPlatform(targetLinuxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-linux-amd64-full.tar.gz") jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-linux-amd64-full.tar.gz")
} }
targetPlatform(targetOsxAarch64) { targetPlatform(targetOsxAarch64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-macos-aarch64-full.tar.gz") jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-macos-aarch64-full.tar.gz")
} }
targetPlatform(targetOsxX86_64) { targetPlatform(targetOsxX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-macos-amd64-full.tar.gz") jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-macos-amd64-full.tar.gz")
} }
targetPlatform(targetWindowsX86_64) { targetPlatform(targetWindowsX86_64) {
jdkHome = jdkDownload("https://download.bell-sw.com/java/17.0.2+9/bellsoft-jdk17.0.2+9-windows-amd64-full.zip") jdkHome = jdkDownload("https://download.bell-sw.com/java/18.0.1+12/bellsoft-jdk18.0.1+12-windows-amd64-full.zip")
} }
} }
//Build using pre-downloaded JDKs //Build using pre-downloaded JDKs

View File

@@ -1,5 +1,24 @@
#
# ******************************************************************************
# Copyright (C) 2014-2022 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 <http://www.gnu.org/licenses/>
# *****************************************************************************
#
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.alias; package io.github.dsheirer.alias;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.alias; package io.github.dsheirer.alias;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.alias; package io.github.dsheirer.alias;

View File

@@ -39,7 +39,7 @@ public class AudioSegmentBroadcaster<T extends AudioSegment> extends Broadcaster
@Override @Override
public void broadcast(T audioSegment) public void broadcast(T audioSegment)
{ {
for(Listener<T> listener : mListeners) for(Listener<T> listener : getListeners())
{ {
audioSegment.incrementConsumerCount(); audioSegment.incrementConsumerCount();
listener.receive(audioSegment); listener.receive(audioSegment);

View File

@@ -24,7 +24,10 @@ import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.Float;
import java.lang.Math;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AudioUtils public class AudioUtils
@@ -78,4 +81,43 @@ public class AudioUtils
return stream.toByteArray(); return stream.toByteArray();
} }
/**
* Normalize audio samples
*/
public static List<float[]> normalize(List<float[]> audioBuffers)
{
float targetMax = 0.95f; // -0.44dBFS
float max = 0.1f; // Initialize at 0.1 (-20dBFS) to limit maximum gain
for(float[] audioBuffer: audioBuffers)
{
for(float value: audioBuffer)
{
float newMax = Math.max(max, Math.abs(value));
if(!Float.isNaN(newMax))
{
max = newMax;
}
}
}
if(targetMax == max)
{
return audioBuffers;
}
float gain = targetMax / max;
for(float[] audioBuffer: audioBuffers)
{
for(int i=0;i<audioBuffer.length;i++)
{
audioBuffer[i] *= gain;
}
}
return audioBuffers;
}
} }

View File

@@ -42,7 +42,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
private final static Logger mLog = LoggerFactory.getLogger(AudioStreamingBroadcaster.class); private final static Logger mLog = LoggerFactory.getLogger(AudioStreamingBroadcaster.class);
public static final int PROCESSOR_RUN_INTERVAL_MS = 1000; public static final int PROCESSOR_RUN_INTERVAL_MS = 1000;
private ScheduledFuture mRecordingQueueProcessorFuture; private ScheduledFuture<?> mRecordingQueueProcessorFuture;
private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor(); private RecordingQueueProcessor mRecordingQueueProcessor = new RecordingQueueProcessor();
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>(); private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
@@ -52,6 +52,10 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
private long mMaximumRecordingAge; private long mMaximumRecordingAge;
private AtomicBoolean mStreaming = new AtomicBoolean(); private AtomicBoolean mStreaming = new AtomicBoolean();
protected boolean mInlineActive = false;
protected int mInlineInterval;
protected int mInlineRemaining = -1;
/** /**
* AudioBroadcaster for streaming audio recordings to a remote streaming audio server. Audio recordings are * AudioBroadcaster for streaming audio recordings to a remote streaming audio server. Audio recordings are
* generated by an internal StreamManager that converts an inbound stream of AudioPackets into a recording of the * generated by an internal StreamManager that converts an inbound stream of AudioPackets into a recording of the
@@ -89,7 +93,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
/** /**
* Broadcast binary audio data frames or sequences. * Broadcast binary audio data frames or sequences.
*/ */
protected abstract void broadcastAudio(byte[] audio); protected abstract void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection);
/** /**
* Protocol-specific metadata updater * Protocol-specific metadata updater
@@ -205,13 +209,15 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
super.setBroadcastState(state); super.setBroadcastState(state);
if(mBroadcastState.get() instanceof BroadcastState && ((BroadcastState)mBroadcastState.get()).isErrorState()) if(mBroadcastState.get() != null && mBroadcastState.get().isErrorState())
{ {
stop(); stop();
} }
if(!connected()) if(!connected())
{ {
//Reset inline metadata
mInlineRemaining = -1;
//Remove all pending audio recordings //Remove all pending audio recordings
while(!mAudioRecordingQueue.isEmpty()) while(!mAudioRecordingQueue.isEmpty())
{ {
@@ -265,9 +271,9 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{ {
private AtomicBoolean mProcessing = new AtomicBoolean(); private AtomicBoolean mProcessing = new AtomicBoolean();
private ByteArrayInputStream mInputStream; private ByteArrayInputStream mInputStream;
private IdentifierCollection mInputIdentifierCollection;
private long mFinalSilencePadding = 0; private long mFinalSilencePadding = 0;
private int mBytesStreamedActual = 0; private int mBytesToStreamPerInterval = 0;
private int mBytesStreamedRequired = 0;
@Override @Override
public void run() public void run()
@@ -278,51 +284,44 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{ {
if(mInputStream == null || mInputStream.available() <= 0) if(mInputStream == null || mInputStream.available() <= 0)
{ {
if(mFinalSilencePadding > 0)
{
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
for(byte[] silence: finalSilence)
{
broadcastAudio(silence);
}
mFinalSilencePadding = 0;
}
nextRecording(); nextRecording();
} }
if(mInputStream != null) if(mInputStream != null)
{ {
//We need to stream at 13.888 fps (144 byte frame) to achieve 2000 Bps or 16 kbps int length = FastMath.min(mBytesToStreamPerInterval, mInputStream.available());
mBytesStreamedRequired += 2000; //2000 bytes per second for 16 kbps data rate
int bytesToStream = mBytesStreamedRequired - mBytesStreamedActual;
//Trim length to whole-frame intervals (144 byte frame)
bytesToStream -= (bytesToStream % 144);
int length = FastMath.min(bytesToStream, mInputStream.available());
byte[] audio = new byte[length]; byte[] audio = new byte[length];
try try
{ {
mBytesStreamedActual += mInputStream.read(audio); int read = mInputStream.read(audio);
broadcastAudio(audio, mInputIdentifierCollection);
broadcastAudio(audio);
} }
catch(IOException ioe) catch(IOException ioe)
{ {
mLog.error("Error reading from in-memory audio recording input stream", ioe); mLog.error("Error reading from in-memory audio recording input stream", ioe);
} }
//If this is the final frame fragment then append silence padding to fill the final interval segment
if(length < mBytesToStreamPerInterval && mFinalSilencePadding > 0)
{
List<byte[]> finalSilence = mSilenceGenerator.generate(mFinalSilencePadding);
for(byte[] silence: finalSilence)
{
broadcastAudio(silence, null);
}
mFinalSilencePadding = 0;
}
} }
else else
{ {
List<byte[]> silenceFrames = mSilenceGenerator.generate(PROCESSOR_RUN_INTERVAL_MS); List<byte[]> silenceFrames = mSilenceGenerator.generate(PROCESSOR_RUN_INTERVAL_MS);
for(byte[] silence: silenceFrames) for(byte[] silence: silenceFrames)
{ {
broadcastAudio(silence); broadcastAudio(silence, null);
} }
} }
} }
@@ -340,9 +339,6 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
*/ */
private void nextRecording() private void nextRecording()
{ {
mBytesStreamedActual = 0;
mBytesStreamedRequired = 0;
boolean metadataUpdateRequired = false; boolean metadataUpdateRequired = false;
if(mInputStream != null) if(mInputStream != null)
@@ -354,6 +350,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
} }
mInputStream = null; mInputStream = null;
mInputIdentifierCollection = null;
//Peek at the next recording but don't remove it from the queue yet, so we can inspect the start time for //Peek at the next recording but don't remove it from the queue yet, so we can inspect the start time for
//age limits and/or delay elapsed //age limits and/or delay elapsed
@@ -381,9 +378,14 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
{ {
byte[] audio = Files.readAllBytes(nextRecording.getPath()); byte[] audio = Files.readAllBytes(nextRecording.getPath());
if(audio != null && audio.length > 0) if(audio.length > 0)
{ {
//Calculate how many bytes we'll send with each processor run interval
double intervals = (double)nextRecording.getRecordingLength() / (double)PROCESSOR_RUN_INTERVAL_MS;
mBytesToStreamPerInterval = (int)((double)audio.length / intervals);
mInputStream = new ByteArrayInputStream(audio); mInputStream = new ByteArrayInputStream(audio);
mInputIdentifierCollection = nextRecording.getIdentifierCollection();
mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS - mFinalSilencePadding = PROCESSOR_RUN_INTERVAL_MS -
(nextRecording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS); (nextRecording.getRecordingLength() % PROCESSOR_RUN_INTERVAL_MS);
@@ -408,6 +410,7 @@ public abstract class AudioStreamingBroadcaster<T extends BroadcastConfiguration
"stream recording [" + nextRecording.getPath().toString() + "] - skipping recording - ", ioe); "stream recording [" + nextRecording.getPath().toString() + "] - skipping recording - ", ioe);
mInputStream = null; mInputStream = null;
mInputIdentifierCollection = null;
metadataUpdateRequired = false; metadataUpdateRequired = false;
} }

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.audio.broadcast; package io.github.dsheirer.audio.broadcast;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.audio.broadcast; package io.github.dsheirer.audio.broadcast;

View File

@@ -68,6 +68,7 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
private static final String MULTIPART_TYPE = "multipart"; private static final String MULTIPART_TYPE = "multipart";
private static final String DEFAULT_SUBTYPE = "form-data"; private static final String DEFAULT_SUBTYPE = "form-data";
private static final String MULTIPART_FORM_DATA = MULTIPART_TYPE + "/" + DEFAULT_SUBTYPE; private static final String MULTIPART_FORM_DATA = MULTIPART_TYPE + "/" + DEFAULT_SUBTYPE;
private ScheduledFuture<?> mBroadcastifyTestFuture;
private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>(); private Queue<AudioRecording> mAudioRecordingQueue = new LinkedTransferQueue<>();
private ScheduledFuture<?> mAudioRecordingProcessorFuture; private ScheduledFuture<?> mAudioRecordingProcessorFuture;
private HttpClient mHttpClient = HttpClient.newBuilder() private HttpClient mHttpClient = HttpClient.newBuilder()
@@ -109,6 +110,12 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
setBroadcastState(BroadcastState.ERROR); setBroadcastState(BroadcastState.ERROR);
} }
if(mBroadcastifyTestFuture == null && getBroadcastConfiguration().isTestEnabled())
{
// Test periodically so we don't get marked offline due to radio inactivity
mBroadcastifyTestFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new BroadcastifyCallTest(), getBroadcastConfiguration().getTestInterval(), getBroadcastConfiguration().getTestInterval(), TimeUnit.MINUTES);
}
if(mAudioRecordingProcessorFuture == null) if(mAudioRecordingProcessorFuture == null)
{ {
mAudioRecordingProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioRecordingProcessor(), mAudioRecordingProcessorFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new AudioRecordingProcessor(),
@@ -122,6 +129,11 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
@Override @Override
public void stop() public void stop()
{ {
if(mBroadcastifyTestFuture != null)
{
mBroadcastifyTestFuture.cancel(true);
mBroadcastifyTestFuture = null;
}
if(mAudioRecordingProcessorFuture != null) if(mAudioRecordingProcessorFuture != null)
{ {
mAudioRecordingProcessorFuture.cancel(true); mAudioRecordingProcessorFuture.cancel(true);
@@ -131,6 +143,23 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster<Broadc
} }
} }
public class BroadcastifyCallTest implements Runnable
{
@Override
public void run()
{
String response = testConnection(getBroadcastConfiguration());
if(response != null && response.toLowerCase().startsWith("ok"))
{
mLog.info("Broadcastify Calls keep-alive success");
}
else
{
mLog.info("Broadcastify Calls keep-alive failure");
}
}
}
/** /**
* Prepares for disposal * Prepares for disposal
*/ */

View File

@@ -24,7 +24,9 @@ import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.audio.broadcast.BroadcastFormat; import io.github.dsheirer.audio.broadcast.BroadcastFormat;
import io.github.dsheirer.audio.broadcast.BroadcastServerType; import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@@ -42,6 +44,8 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
private IntegerProperty mSystemID = new SimpleIntegerProperty(); private IntegerProperty mSystemID = new SimpleIntegerProperty();
private StringProperty mApiKey = new SimpleStringProperty(); private StringProperty mApiKey = new SimpleStringProperty();
private BooleanProperty mTestEnabled= new SimpleBooleanProperty(false);
private IntegerProperty mTestInterval = new SimpleIntegerProperty(15);
/** /**
* Constructor for faster jackson * Constructor for faster jackson
@@ -128,6 +132,34 @@ public class BroadcastifyCallConfiguration extends BroadcastConfiguration
return BroadcastServerType.BROADCASTIFY_CALL; return BroadcastServerType.BROADCASTIFY_CALL;
} }
/**
* Indicates if this instance should schedule tests after connecting
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_enabled")
public boolean isTestEnabled()
{
return mTestEnabled.get();
}
public void setTestEnabled(boolean enabled)
{
mTestEnabled.set(enabled);
}
/**
* Indicates the interval at which tests should be performed while enabled
*/
@JacksonXmlProperty(isAttribute = true, localName = "test_interval")
public int getTestInterval()
{
return mTestInterval.get();
}
public void setTestInterval(int interval)
{
mTestInterval.set(interval);
}
@Override @Override
public BroadcastConfiguration copyOf() public BroadcastConfiguration copyOf()
{ {

View File

@@ -54,6 +54,7 @@ public class BroadcastifyFeedConfiguration extends IcecastTCPConfiguration
setBitRate(16); setBitRate(16);
setChannels(1); setChannels(1);
setSampleRate(8000); setSampleRate(8000);
setInline(true);
} }
public static BroadcastifyFeedConfiguration from(UserFeedBroadcast userFeedBroadcast) public static BroadcastifyFeedConfiguration from(UserFeedBroadcast userFeedBroadcast)
@@ -86,9 +87,9 @@ public class BroadcastifyFeedConfiguration extends IcecastTCPConfiguration
copy.setName(getName()); copy.setName(getName());
copy.setHost(getHost()); copy.setHost(getHost());
copy.setPort(getPort()); copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword()); copy.setPassword(getPassword());
copy.setDelay(getDelay()); copy.setDelay(getDelay());
copy.setEnabled(false); copy.setEnabled(false);
//Icecast Configuration Parameters //Icecast Configuration Parameters

View File

@@ -28,7 +28,7 @@ import io.github.dsheirer.audio.convert.MP3Setting;
public abstract class IcecastAudioBroadcaster extends AudioStreamingBroadcaster public abstract class IcecastAudioBroadcaster extends AudioStreamingBroadcaster
{ {
private IBroadcastMetadataUpdater mMetadataUpdater; private IBroadcastMetadataUpdater mMetadataUpdater;
private AliasModel mAliasModel; protected AliasModel mAliasModel;
public IcecastAudioBroadcaster(BroadcastConfiguration broadcastConfiguration, InputAudioFormat inputAudioFormat, public IcecastAudioBroadcaster(BroadcastConfiguration broadcastConfiguration, InputAudioFormat inputAudioFormat,
MP3Setting mp3Setting, AliasModel aliasModel) MP3Setting mp3Setting, AliasModel aliasModel)

View File

@@ -23,6 +23,8 @@ import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasList; import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater; import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater;
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.identifier.Form; import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierClass; import io.github.dsheirer.identifier.IdentifierClass;
@@ -73,6 +75,12 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
*/ */
public void update(IdentifierCollection identifierCollection) public void update(IdentifierCollection identifierCollection)
{ {
if(mIcecastConfiguration.hasInline())
{
// Never send out-of-band metadata if inline metadata is enabled.
return;
}
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
try try
@@ -84,7 +92,7 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
sb.append("/admin/metadata?mode=updinfo&mount="); sb.append("/admin/metadata?mode=updinfo&mount=");
sb.append(URLEncoder.encode(mIcecastConfiguration.getMountPoint(), UTF8)); sb.append(URLEncoder.encode(mIcecastConfiguration.getMountPoint(), UTF8));
sb.append("&charset=UTF%2d8"); sb.append("&charset=UTF%2d8");
sb.append("&song=").append(URLEncoder.encode(getSong(identifierCollection), UTF8)); sb.append("&song=").append(URLEncoder.encode(IcecastMetadata.getTitle(identifierCollection, mAliasModel), UTF8));
} }
catch(UnsupportedEncodingException uee) catch(UnsupportedEncodingException uee)
{ {
@@ -157,82 +165,4 @@ public class IcecastBroadcastMetadataUpdater implements IBroadcastMetadataUpdate
} }
} }
/**
* Creates the song information for a metadata update
*/
private String getSong(IdentifierCollection identifierCollection)
{
StringBuilder sb = new StringBuilder();
if(identifierCollection != null)
{
AliasList aliasList = mAliasModel.getAliasList(identifierCollection);
Identifier to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.PATCH_GROUP, Role.TO);
if(to == null)
{
to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.TO);
}
if(to == null)
{
List<Identifier> toIdentifiers = identifierCollection.getIdentifiers(Role.TO);
if(!toIdentifiers.isEmpty())
{
to = toIdentifiers.get(0);
}
}
if(to != null)
{
sb.append("TO:").append(to);
List<Alias> aliases = aliasList.getAliases(to);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append("TO:UNKNOWN");
}
Identifier from = identifierCollection.getIdentifier(IdentifierClass.USER, Form.RADIO, Role.FROM);
if(from == null)
{
List<Identifier> fromIdentifiers = identifierCollection.getIdentifiers(Role.FROM);
if(!fromIdentifiers.isEmpty())
{
from = fromIdentifiers.get(0);
}
}
if(from != null)
{
sb.append(" FROM:").append(from);
List<Alias> aliases = aliasList.getAliases(from);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append(" FROM:UNKNOWN");
}
}
else
{
sb.append("Scanning ....");
}
return sb.toString();
}
} }

View File

@@ -45,6 +45,7 @@ public abstract class IcecastConfiguration extends BroadcastConfiguration
private int mChannels = 1; private int mChannels = 1;
private int mSampleRate = 8000; private int mSampleRate = 8000;
private String mURL; private String mURL;
private boolean mInline = true;
public IcecastConfiguration(BroadcastFormat format) public IcecastConfiguration(BroadcastFormat format)
{ {
@@ -275,6 +276,37 @@ public abstract class IcecastConfiguration extends BroadcastConfiguration
return mURL != null; return mURL != null;
} }
/**
* Control whether metadata is sent inline or out-of-band.
*/
@JacksonXmlProperty(isAttribute = true, localName = "inline")
public boolean getInline()
{
return mInline;
}
@JsonIgnore
public int getInlineInterval()
{
if (hasBitRate())
{
// Interval = BitRate * 1000 / 8 = 1 second
return getBitRate() * 125;
}
return -1;
}
public void setInline(boolean inline)
{
mInline = inline;
}
public boolean hasInline()
{
// Bitrate must be known to calculate metadata interval
return mInline != false && hasBitRate();
}
@Override @Override
public boolean isValid() public boolean isValid()
{ {

View File

@@ -20,9 +20,11 @@ package io.github.dsheirer.audio.broadcast.icecast;
import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastState; import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.audio.convert.InputAudioFormat; import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3AudioConverter; import io.github.dsheirer.audio.convert.MP3AudioConverter;
import io.github.dsheirer.audio.convert.MP3Setting; import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.properties.SystemProperties; import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException; import org.apache.mina.core.RuntimeIoException;
@@ -42,6 +44,7 @@ import org.slf4j.LoggerFactory;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -80,14 +83,41 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster
* Broadcasts the audio frame or sequence * Broadcasts the audio frame or sequence
*/ */
@Override @Override
protected void broadcastAudio(byte[] audio) protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{ {
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected()) if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{ {
IoBuffer buffer = IoBuffer.allocate(audio.length); IoBuffer buffer = IoBuffer.allocate(audio.length);
buffer.put(audio);
buffer.flip();
if(mInlineActive)
{
byte[] metadata = IcecastMetadata.formatInline(IcecastMetadata.getTitle(identifierCollection, mAliasModel)).getBytes();
buffer.setAutoExpand(true);
if (mInlineRemaining == -1)
{
mInlineRemaining = mInlineInterval;
}
int audioOffset = 0;
while(audioOffset < audio.length)
{
byte[] chunk = Arrays.copyOfRange(audio, audioOffset, Math.min(audioOffset + mInlineRemaining, audio.length));
mInlineRemaining -= chunk.length;
audioOffset += chunk.length;
buffer.put(chunk);
if(mInlineRemaining == 0)
{
mInlineRemaining = mInlineInterval;
buffer.put(metadata);
}
}
buffer.shrink();
}
else
{
buffer.put(audio);
}
buffer.flip();
mStreamingSession.write(buffer); mStreamingSession.write(buffer);
} }
} }
@@ -238,6 +268,17 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster
{ {
mHTTPHeaders.put(IcecastHeader.BITRATE.getValue(), String.valueOf(getConfiguration().getBitRate())); mHTTPHeaders.put(IcecastHeader.BITRATE.getValue(), String.valueOf(getConfiguration().getBitRate()));
} }
if(getConfiguration().hasInline())
{
mInlineActive = true;
mInlineInterval = getConfiguration().getInlineInterval();
mHTTPHeaders.put(IcecastHeader.METAINT.getValue(), String.valueOf(mInlineInterval));
}
else
{
mInlineActive = false;
}
} }
return mHTTPHeaders; return mHTTPHeaders;

View File

@@ -55,6 +55,7 @@ public class IcecastHTTPConfiguration extends IcecastConfiguration
copy.setName(getName()); copy.setName(getName());
copy.setHost(getHost()); copy.setHost(getHost());
copy.setPort(getPort()); copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword()); copy.setPassword(getPassword());
copy.setDelay(getDelay()); copy.setDelay(getDelay());
copy.setEnabled(false); copy.setEnabled(false);

View File

@@ -33,6 +33,7 @@ public enum IcecastHeader
PUBLIC("ice-public"), PUBLIC("ice-public"),
URL("ice-url"), URL("ice-url"),
USER_AGENT("User-Agent"), USER_AGENT("User-Agent"),
METAINT("icy-metaint"),
UNKNOWN("unknown"); UNKNOWN("unknown");

View File

@@ -0,0 +1,138 @@
/*
*
* * ******************************************************************************
* * Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
*
*
*/
package io.github.dsheirer.audio.broadcast.icecast;
import com.google.common.base.Joiner;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
import io.github.dsheirer.identifier.Form;
import io.github.dsheirer.identifier.Identifier;
import io.github.dsheirer.identifier.IdentifierClass;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
public class IcecastMetadata
{
private final static Logger mLog = LoggerFactory.getLogger(IcecastMetadata.class);
/**
* Creates the title for a metadata update
*/
public static String getTitle(IdentifierCollection identifierCollection, AliasModel AliasModel)
{
StringBuilder sb = new StringBuilder();
if(identifierCollection != null)
{
AliasList aliasList = AliasModel.getAliasList(identifierCollection);
Identifier to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.PATCH_GROUP, Role.TO);
if(to == null)
{
to = identifierCollection.getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.TO);
}
if(to == null)
{
List<Identifier> toIdentifiers = identifierCollection.getIdentifiers(Role.TO);
if(!toIdentifiers.isEmpty())
{
to = toIdentifiers.get(0);
}
}
if(to != null)
{
sb.append("TO:").append(to);
List<Alias> aliases = aliasList.getAliases(to);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append("TO:UNKNOWN");
}
Identifier from = identifierCollection.getIdentifier(IdentifierClass.USER, Form.RADIO, Role.FROM);
if(from == null)
{
List<Identifier> fromIdentifiers = identifierCollection.getIdentifiers(Role.FROM);
if(!fromIdentifiers.isEmpty())
{
from = fromIdentifiers.get(0);
}
}
if(from != null)
{
sb.append(" FROM:").append(from);
List<Alias> aliases = aliasList.getAliases(from);
if(aliases != null && !aliases.isEmpty())
{
sb.append(" ").append(Joiner.on(", ").skipNulls().join(aliases));
}
}
else
{
sb.append(" FROM:UNKNOWN");
}
}
else
{
sb.append("Scanning...");
}
return sb.toString();
}
public static String formatInline(String title)
{
title = "StreamTitle='" + title + "';";
int chunks = (int)Math.ceil((title.length() + 1) / 16.0d);
int nulls = (chunks * 16) - title.length();
char[] padding = new char[nulls];
StringBuilder sb = new StringBuilder();
sb.append((char)chunks).append(title).append(padding);
return sb.toString();
}
}

View File

@@ -21,9 +21,11 @@ package io.github.dsheirer.audio.broadcast.icecast;
import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastState; import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.icecast.codec.IcecastCodecFactory; import io.github.dsheirer.audio.broadcast.icecast.codec.IcecastCodecFactory;
import io.github.dsheirer.audio.broadcast.icecast.IcecastMetadata;
import io.github.dsheirer.audio.convert.InputAudioFormat; import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3AudioConverter; import io.github.dsheirer.audio.convert.MP3AudioConverter;
import io.github.dsheirer.audio.convert.MP3Setting; import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.properties.SystemProperties; import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException; import org.apache.mina.core.RuntimeIoException;
@@ -39,13 +41,14 @@ import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketException; import java.net.SocketException;
import java.nio.channels.UnresolvedAddressException; import java.nio.channels.UnresolvedAddressException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
{ {
private final static Logger mLog = LoggerFactory.getLogger(IcecastTCPAudioBroadcaster.class); private final static Logger mLog = LoggerFactory.getLogger(IcecastTCPAudioBroadcaster.class);
private final static String TERMINATOR = "\r\n"; private final static String TERMINATOR = "\n";
private final static String SEPARATOR = ":"; private final static String SEPARATOR = ":";
private static final long RECONNECT_INTERVAL_MILLISECONDS = 3000; //3 seconds private static final long RECONNECT_INTERVAL_MILLISECONDS = 3000; //3 seconds
private static final long CONNECTION_ATTEMPT_TIMEOUT_MILLISECONDS = 5000; //5 seconds private static final long CONNECTION_ATTEMPT_TIMEOUT_MILLISECONDS = 5000; //5 seconds
@@ -78,11 +81,35 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
* Broadcasts the audio frame or sequence * Broadcasts the audio frame or sequence
*/ */
@Override @Override
protected void broadcastAudio(byte[] audio) protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{ {
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected()) if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{ {
mStreamingSession.write(audio); if(mInlineActive)
{
byte[] metadata = IcecastMetadata.formatInline(IcecastMetadata.getTitle(identifierCollection, mAliasModel)).getBytes();
if (mInlineRemaining == -1)
{
mInlineRemaining = mInlineInterval;
}
int audioOffset = 0;
while(audioOffset < audio.length)
{
byte[] chunk = Arrays.copyOfRange(audio, audioOffset, Math.min(audioOffset + mInlineRemaining, audio.length));
mInlineRemaining -= chunk.length;
audioOffset += chunk.length;
mStreamingSession.write(chunk);
if(mInlineRemaining == 0)
{
mInlineRemaining = mInlineInterval;
mStreamingSession.write(metadata);
}
}
}
else
{
mStreamingSession.write(audio);
}
} }
} }
@@ -238,7 +265,18 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster
.append(getConfiguration().getDescription()).append(TERMINATOR); .append(getConfiguration().getDescription()).append(TERMINATOR);
} }
sb.append(TERMINATOR).append(TERMINATOR); if(getConfiguration().hasInline())
{
mInlineActive = true;
mInlineInterval = getConfiguration().getInlineInterval();
sb.append(IcecastHeader.METAINT.getValue()).append(SEPARATOR)
.append(String.valueOf(mInlineInterval))
.append(TERMINATOR);
}
else
{
mInlineActive = false;
}
session.write(sb.toString()); session.write(sb.toString());
} }

View File

@@ -63,6 +63,7 @@ public class IcecastTCPConfiguration extends IcecastConfiguration
copy.setName(getName()); copy.setName(getName());
copy.setHost(getHost()); copy.setHost(getHost());
copy.setPort(getPort()); copy.setPort(getPort());
copy.setInline(getInline());
copy.setPassword(getPassword()); copy.setPassword(getPassword());
copy.setDelay(getDelay()); copy.setDelay(getDelay());
copy.setEnabled(false); copy.setEnabled(false);

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.audio.broadcast.icecast.codec; package io.github.dsheirer.audio.broadcast.icecast.codec;
import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.IoBuffer;

View File

@@ -24,6 +24,7 @@ import io.github.dsheirer.audio.broadcast.BroadcastState;
import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater; import io.github.dsheirer.audio.broadcast.IBroadcastMetadataUpdater;
import io.github.dsheirer.audio.convert.InputAudioFormat; import io.github.dsheirer.audio.convert.InputAudioFormat;
import io.github.dsheirer.audio.convert.MP3Setting; import io.github.dsheirer.audio.convert.MP3Setting;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import org.apache.mina.core.RuntimeIoException; import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.buffer.IoBuffer;
@@ -93,7 +94,7 @@ public class ShoutcastV1AudioBroadcaster extends AudioStreamingBroadcaster
* Broadcasts the audio frame or sequence * Broadcasts the audio frame or sequence
*/ */
@Override @Override
protected void broadcastAudio(byte[] audio) protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{ {
if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected()) if(audio != null && audio.length > 0 && connect() && mStreamingSession != null && mStreamingSession.isConnected())
{ {

View File

@@ -109,7 +109,7 @@ public class ShoutcastV2AudioStreamingBroadcaster extends AudioStreamingBroadcas
* Broadcasts the audio frame or sequence * Broadcasts the audio frame or sequence
*/ */
@Override @Override
protected void broadcastAudio(byte[] audio) protected void broadcastAudio(byte[] audio, IdentifierCollection identifierCollection)
{ {
//Dispatch any queued metadata messages //Dispatch any queued metadata messages
UltravoxMessage metadataMessage = mMetadataMessageQueue.poll(); UltravoxMessage metadataMessage = mMetadataMessageQueue.poll();

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox; package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox;
import io.github.dsheirer.audio.broadcast.BroadcastFormat; import io.github.dsheirer.audio.broadcast.BroadcastFormat;

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox; package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox;
import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.BinaryMessage;

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox; package io.github.dsheirer.audio.broadcast.shoutcast.v2.ultravox;
public class UltravoxMessageFactory public class UltravoxMessageFactory

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -18,6 +18,7 @@
*/ */
package io.github.dsheirer.audio.convert; package io.github.dsheirer.audio.convert;
import io.github.dsheirer.audio.AudioUtils;
import io.github.dsheirer.dsp.filter.resample.RealResampler; import io.github.dsheirer.dsp.filter.resample.RealResampler;
import io.github.dsheirer.sample.ConversionUtils; import io.github.dsheirer.sample.ConversionUtils;
import net.sourceforge.lame.lowlevel.LameEncoder; import net.sourceforge.lame.lowlevel.LameEncoder;
@@ -73,6 +74,7 @@ public class MP3AudioConverter implements IAudioConverter
public List<byte[]> convert(List<float[]> audioPackets) public List<byte[]> convert(List<float[]> audioPackets)
{ {
List<byte[]> converted = new ArrayList<>(); List<byte[]> converted = new ArrayList<>();
audioPackets = AudioUtils.normalize(audioPackets);
if(mResampler != null) if(mResampler != null)
{ {

View File

@@ -34,8 +34,8 @@ public enum MP3Setting
CBR_16(false, 16, "CBR - Constant Bit Rate 16 kbps (default)"), CBR_16(false, 16, "CBR - Constant Bit Rate 16 kbps (default)"),
CBR_32(false, 32, "CBR - Constant Bit Rate 32 kbps"), CBR_32(false, 32, "CBR - Constant Bit Rate 32 kbps"),
ABR_56(true, 56, "ABR - Average Bit Rate 56 kbps"), ABR_56(true, 56, "ABR - Average Bit Rate 56 kbps"),
VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Middle Quality (5)"), VBR_5(true, Lame.QUALITY_MIDDLE, "VBR - Variable Bit Rate - Better Quality"),
VBR_7(true, Lame.QUALITY_LOW, "VBR - Low Quality (7)"); VBR_7(true, Lame.QUALITY_LOW, "VBR - Variable Bit Rate - Good Quality");
private boolean mVariableBitRate; private boolean mVariableBitRate;
private int mSetting; private int mSetting;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.audio.convert.thumbdv.message; package io.github.dsheirer.audio.convert.thumbdv.message;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.audio.convert.thumbdv.message.response; package io.github.dsheirer.audio.convert.thumbdv.message.response;

View File

@@ -1,7 +1,6 @@
/* /*
* ****************************************************************************** * *****************************************************************************
* sdrtrunk * Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2018 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* ***************************************************************************** * ****************************************************************************
*/ */
package io.github.dsheirer.audio.playback; package io.github.dsheirer.audio.playback;
@@ -30,7 +29,6 @@ import io.github.dsheirer.icon.IconModel;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.mixer.MixerChannelConfiguration; import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
import jiconfont.icons.font_awesome.FontAwesome; import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.swing.IconFontSwing; import jiconfont.swing.IconFontSwing;
@@ -69,7 +67,6 @@ public class AudioPanel extends JPanel implements Listener<AudioEvent>
private IconModel mIconModel; private IconModel mIconModel;
private SettingsManager mSettingsManager; private SettingsManager mSettingsManager;
private SourceManager mSourceManager;
private IAudioController mController; private IAudioController mController;
private AliasModel mAliasModel; private AliasModel mAliasModel;
private UserPreferences mUserPreferences; private UserPreferences mUserPreferences;
@@ -78,11 +75,10 @@ public class AudioPanel extends JPanel implements Listener<AudioEvent>
private AudioChannelsPanel mAudioChannelsPanel; private AudioChannelsPanel mAudioChannelsPanel;
public AudioPanel(IconModel iconModel, UserPreferences userPreferences, SettingsManager settingsManager, public AudioPanel(IconModel iconModel, UserPreferences userPreferences, SettingsManager settingsManager,
SourceManager sourceManager, IAudioController controller, AliasModel aliasModel) IAudioController controller, AliasModel aliasModel)
{ {
mIconModel = iconModel; mIconModel = iconModel;
mSettingsManager = settingsManager; mSettingsManager = settingsManager;
mSourceManager = sourceManager;
mController = controller; mController = controller;
mAliasModel = aliasModel; mAliasModel = aliasModel;
mUserPreferences = userPreferences; mUserPreferences = userPreferences;

View File

@@ -35,7 +35,7 @@ public class BinaryMessage extends BitSet
* Logical (ie constructed) size of this bitset, despite the actual size of * Logical (ie constructed) size of this bitset, despite the actual size of
* the super bitset that this class is based on * the super bitset that this class is based on
*/ */
private int mSize = 0; private int mSize;
/** /**
* Pointer to the next fill index location, when adding bits to this bitset * Pointer to the next fill index location, when adding bits to this bitset
@@ -43,21 +43,21 @@ public class BinaryMessage extends BitSet
*/ */
private int mPointer = 0; private int mPointer = 0;
/**
* Bitset that buffers bits added one at a time, up to the size of the this
* bitset.
*
* Note: the super class bitset behind this class may have a size larger
* that the size parameter specified.
* @param size
*/
/** /**
* Used for temporary storage of CRC check results when we're passing this * Used for temporary storage of CRC check results when we're passing this
* message to an EDAC function. * message to an EDAC function.
*/ */
private CRC mCRC; private CRC mCRC;
/**
* Constructs a bitset that buffers bits added one at a time, up to the size
* of the this bitset.
* <p>
* Note: the super class bitset behind this class may have a size larger
* that the size parameter specified.
*
* @param size of constructed bitset
*/
public BinaryMessage(int size) public BinaryMessage(int size)
{ {
super(size); super(size);
@@ -214,9 +214,7 @@ public class BinaryMessage extends BitSet
} }
/** /**
* Returns a (new) copy of this bitsetbuffer * @return a (new) copy of this binary message
*
* @return
*/ */
public BinaryMessage copy() public BinaryMessage copy()
{ {

View File

@@ -1,20 +1,21 @@
/******************************************************************************* /*
* SDR Trunk * *****************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/ * ****************************************************************************
*/
package io.github.dsheirer.buffer; package io.github.dsheirer.buffer;
import io.github.dsheirer.sample.complex.Complex; import io.github.dsheirer.sample.complex.Complex;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2017 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.buffer; package io.github.dsheirer.buffer;
/** /**

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.metadata; package io.github.dsheirer.channel.metadata;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.state; package io.github.dsheirer.channel.state;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.state; package io.github.dsheirer.channel.state;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.state; package io.github.dsheirer.channel.state;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.state; package io.github.dsheirer.channel.state;

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.channel.state; package io.github.dsheirer.channel.state;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -30,8 +30,8 @@ import io.github.dsheirer.map.MapService;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager; import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.TunerViewPanel; import io.github.dsheirer.source.tuner.ui.TunerViewPanel;
import jiconfont.icons.font_awesome.FontAwesome; import jiconfont.icons.font_awesome.FontAwesome;
import jiconfont.swing.IconFontSwing; import jiconfont.swing.IconFontSwing;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
@@ -59,13 +59,13 @@ public class ControllerPanel extends JPanel
public ControllerPanel(PlaylistManager playlistManager, AudioPlaybackManager audioPlaybackManager, public ControllerPanel(PlaylistManager playlistManager, AudioPlaybackManager audioPlaybackManager,
IconModel iconModel, MapService mapService, SettingsManager settingsManager, IconModel iconModel, MapService mapService, SettingsManager settingsManager,
SourceManager sourceManager, UserPreferences userPreferences) TunerManager tunerManager, UserPreferences userPreferences)
{ {
mAudioPanel = new AudioPanel(iconModel, userPreferences, settingsManager, sourceManager, audioPlaybackManager, mAudioPanel = new AudioPanel(iconModel, userPreferences, settingsManager, audioPlaybackManager,
playlistManager.getAliasModel()); playlistManager.getAliasModel());
mNowPlayingPanel = new NowPlayingPanel(playlistManager, iconModel, userPreferences); mNowPlayingPanel = new NowPlayingPanel(playlistManager, iconModel, userPreferences);
mMapPanel = new MapPanel(mapService, playlistManager.getAliasModel(), iconModel, settingsManager); mMapPanel = new MapPanel(mapService, playlistManager.getAliasModel(), iconModel, settingsManager);
mTunerManagerPanel = new TunerViewPanel(sourceManager.getTunerModel(), userPreferences); mTunerManagerPanel = new TunerViewPanel(tunerManager, userPreferences);
init(); init();
} }

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.controller.channel; package io.github.dsheirer.controller.channel;
@@ -47,14 +44,15 @@ import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.Source; import io.github.dsheirer.source.Source;
import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.config.SourceConfigTuner; import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import javafx.application.Platform; import javafx.application.Platform;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.awt.GraphicsEnvironment;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -86,7 +84,7 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
private ChannelMapModel mChannelMapModel; private ChannelMapModel mChannelMapModel;
private ChannelMetadataModel mChannelMetadataModel; private ChannelMetadataModel mChannelMetadataModel;
private EventLogManager mEventLogManager; private EventLogManager mEventLogManager;
private SourceManager mSourceManager; private TunerManager mTunerManager;
private AliasModel mAliasModel; private AliasModel mAliasModel;
private UserPreferences mUserPreferences; private UserPreferences mUserPreferences;
private List<Long> mLoggedFrequencies = new ArrayList<>(); private List<Long> mLoggedFrequencies = new ArrayList<>();
@@ -97,16 +95,16 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
* *
* @param channelMapModel containing channel maps defined by the user * @param channelMapModel containing channel maps defined by the user
* @param eventLogManager for adding event loggers to channels * @param eventLogManager for adding event loggers to channels
* @param sourceManager for obtaining a tuner channel source for the channel * @param tunerManager for obtaining a tuner channel source for the channel
* @param aliasModel for aliasing of identifiers produced by the channel * @param aliasModel for aliasing of identifiers produced by the channel
* @param userPreferences for user defined behavior and settings * @param userPreferences for user defined behavior and settings
*/ */
public ChannelProcessingManager(ChannelMapModel channelMapModel, EventLogManager eventLogManager, public ChannelProcessingManager(ChannelMapModel channelMapModel, EventLogManager eventLogManager,
SourceManager sourceManager, AliasModel aliasModel, UserPreferences userPreferences) TunerManager tunerManager, AliasModel aliasModel, UserPreferences userPreferences)
{ {
mChannelMapModel = channelMapModel; mChannelMapModel = channelMapModel;
mEventLogManager = eventLogManager; mEventLogManager = eventLogManager;
mSourceManager = sourceManager; mTunerManager = tunerManager;
mAliasModel = aliasModel; mAliasModel = aliasModel;
mUserPreferences = userPreferences; mUserPreferences = userPreferences;
mChannelMetadataModel = new ChannelMetadataModel(); mChannelMetadataModel = new ChannelMetadataModel();
@@ -303,7 +301,7 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
try try
{ {
source = mSourceManager.getSource(channel.getSourceConfiguration(), source = mTunerManager.getSource(channel.getSourceConfiguration(),
channel.getDecodeConfiguration().getChannelSpecification()); channel.getDecodeConfiguration().getChannelSpecification());
} }
catch(SourceException se) catch(SourceException se)
@@ -439,8 +437,15 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
{ {
processingChain.start(); processingChain.start();
//This has to be done on the FX event thread when the playlist editor is constructed if(GraphicsEnvironment.isHeadless())
Platform.runLater(() -> channel.setProcessing(true)); {
channel.setProcessing(true);
}
else
{
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(true));
}
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_PROCESSING_START)); mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_PROCESSING_START));
} }
@@ -526,13 +531,20 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
*/ */
private void stopProcessing(Channel channel) throws ChannelException private void stopProcessing(Channel channel) throws ChannelException
{ {
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(false));
ProcessingChain processingChain = removeProcessingChain(channel); ProcessingChain processingChain = removeProcessingChain(channel);
if(processingChain != null) if(processingChain != null)
{ {
if(GraphicsEnvironment.isHeadless())
{
channel.setProcessing(false);
}
else
{
//This has to be done on the FX event thread when the playlist editor is constructed
Platform.runLater(() -> channel.setProcessing(false));
}
//Since the processing chain's source will block on stop(), throw it to the thread pool to run //Since the processing chain's source will block on stop(), throw it to the thread pool to run
ThreadPool.CACHED.submit(() -> { ThreadPool.CACHED.submit(() -> {
try try
@@ -558,10 +570,6 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
} }
}); });
} }
else
{
throw new ChannelException("Channel is not currently playing");
}
} }
/** /**
@@ -712,7 +720,9 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
{ {
@Override public void receive(SourceEvent sourceEvent) @Override public void receive(SourceEvent sourceEvent)
{ {
if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_ERROR_STATE && sourceEvent.getSource() != null) if((sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_ERROR_STATE ||
sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_TUNER_SHUTDOWN) &&
sourceEvent.getSource() != null)
{ {
Channel toShutdown = null; Channel toShutdown = null;
@@ -736,7 +746,18 @@ public class ChannelProcessingManager implements Listener<ChannelEvent>
if(toShutdown != null) if(toShutdown != null)
{ {
mLog.warn("Channel source error detected - stopping channel [" + toShutdown.getName() + "]"); if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_ERROR_STATE)
{
mLog.warn("Channel source error detected - stopping channel [" + toShutdown.getName() + "]");
}
else if(sourceEvent.getEvent() == SourceEvent.Event.NOTIFICATION_TUNER_SHUTDOWN)
{
mLog.warn("Tuner removal detected - stopping channel [" + toShutdown.getName() + "]");
}
else
{
mLog.warn("Source event error - stopping channel [" + toShutdown.getName() + "]");
}
try try
{ {

View File

@@ -41,6 +41,7 @@ import org.apache.commons.math3.util.FastMath;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -84,6 +85,7 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
private NativeBufferReceiver mNativeBufferReceiver = new NativeBufferReceiver(); private NativeBufferReceiver mNativeBufferReceiver = new NativeBufferReceiver();
private Dispatcher mBufferDispatcher; private Dispatcher mBufferDispatcher;
private Map<Integer,float[]> mOutputProcessorFilters = new HashMap<>(); private Map<Integer,float[]> mOutputProcessorFilters = new HashMap<>();
private boolean mRunning = true;
/** /**
* Creates a polyphase channel manager instance. * Creates a polyphase channel manager instance.
@@ -126,6 +128,25 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
this(tunerController, tunerController.getFrequency(), tunerController.getSampleRate()); this(tunerController, tunerController.getFrequency(), tunerController.getSampleRate());
} }
public void stopAllChannels()
{
mRunning = false;
List<TunerChannelSource> toStop = new ArrayList<>(mChannelSources);
for(TunerChannelSource tunerChannelSource: toStop)
{
try
{
tunerChannelSource.process(SourceEvent.tunerShutdown(tunerChannelSource));
}
catch(SourceException se)
{
mLog.error("Error stopping tuner channel source for tuner shutdown");
}
}
}
/** /**
* Signals to all provisioned tuner channel sources that the source complex buffer provider has an error and can * Signals to all provisioned tuner channel sources that the source complex buffer provider has an error and can
* no longer provide channels, so that the tuner channel source can notify the consumer of the error state. * no longer provide channels, so that the tuner channel source can notify the consumer of the error state.
@@ -164,24 +185,27 @@ public class PolyphaseChannelManager implements ISourceEventProcessor
{ {
PolyphaseChannelSource channelSource = null; PolyphaseChannelSource channelSource = null;
List<Integer> polyphaseIndexes = mChannelCalculator.getChannelIndexes(tunerChannel); if(mRunning)
IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
if(outputProcessor != null)
{ {
long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes); List<Integer> polyphaseIndexes = mChannelCalculator.getChannelIndexes(tunerChannel);
try IPolyphaseChannelOutputProcessor outputProcessor = getOutputProcessor(polyphaseIndexes);
{
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate(), centerFrequency);
mChannelSources.add(channelSource); if(outputProcessor != null)
}
catch(FilterDesignException fde)
{ {
mLog.debug("Couldn't design final output low pass filter for polyphase channel source"); long centerFrequency = mChannelCalculator.getCenterFrequencyForIndexes(polyphaseIndexes);
try
{
channelSource = new PolyphaseChannelSource(tunerChannel, outputProcessor, mChannelSourceEventListener,
mChannelCalculator.getChannelSampleRate(), centerFrequency);
mChannelSources.add(channelSource);
}
catch(FilterDesignException fde)
{
mLog.debug("Couldn't design final output low pass filter for polyphase channel source");
}
} }
} }

View File

@@ -76,7 +76,7 @@ public class DecimationFilterFactory
*/ */
public static int getDecimationRate(int requestedRate) public static int getDecimationRate(int requestedRate)
{ {
if(requestedRate < 2) if(requestedRate < 0)
{ {
throw new IllegalArgumentException("Requested decimation rate must be greater than 2"); throw new IllegalArgumentException("Requested decimation rate must be greater than 2");
} }

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,3 +1,22 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2022 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.dsp.filter.fir.remez; package io.github.dsheirer.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2017 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.dsp.filter.fir.remez; package io.github.dsheirer.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2017 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,8 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.dsp.filter.fir.remez; package io.github.dsheirer.dsp.filter.fir.remez;
import io.github.dsheirer.dsp.filter.design.FilterDesignException; import io.github.dsheirer.dsp.filter.design.FilterDesignException;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,20 +1,21 @@
/******************************************************************************* /*
* SDR Trunk * *****************************************************************************
* Copyright (C) 2014 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/ * ****************************************************************************
*/
package io.github.dsheirer.edac; package io.github.dsheirer.edac;
import io.github.dsheirer.bits.BinaryMessage; import io.github.dsheirer.bits.BinaryMessage;

View File

@@ -75,7 +75,7 @@ public class FilterEditorPanel<T> extends JPanel
List<IFilter<T>> filters = filterSet.getFilters(); List<IFilter<T>> filters = filterSet.getFilters();
/* sort the filters in alphabetical order by name */ /* sort the filters in alphabetical order by name */
filters.sort((Comparator<IFilter<?>>) (first, second) -> first.getName().compareTo(second.getName())); filters.sort(Comparator.comparing(IFilter::getName));
for(IFilter<T> filter : filters) for(IFilter<T> filter : filters)
{ {
@@ -98,7 +98,7 @@ public class FilterEditorPanel<T> extends JPanel
{ {
List<FilterElement<?>> elements = filter.getFilterElements(); List<FilterElement<?>> elements = filter.getFilterElements();
elements.sort(Comparator.comparing(FilterElement::toString)); elements.sort(Comparator.comparing(FilterElement::getName));
for(FilterElement<?> element : elements) for(FilterElement<?> element : elements)
{ {

View File

@@ -46,13 +46,14 @@ public class FilterSet<T> implements IFilter<T>
{ {
for( IFilter<T> filter: mFilters ) for( IFilter<T> filter: mFilters )
{ {
if( filter.canProcess( t ) ) // Make sure to loop through all filters.
// Only return if true or all filters have been evaluated.
if( filter.canProcess( t ) && filter.passes( t ))
{ {
return filter.passes( t ); return true;
} }
} }
} }
return false; return false;
} }

View File

@@ -41,10 +41,7 @@ import io.github.dsheirer.jmbe.JmbeEditorRequest;
import io.github.dsheirer.module.log.EventLogManager; import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.embed.swing.JFXPanel; import javafx.embed.swing.JFXPanel;
@@ -79,6 +76,7 @@ public class JavaFxWindowManager extends Application
private JmbeEditor mJmbeEditor; private JmbeEditor mJmbeEditor;
private PlaylistEditor mPlaylistEditor; private PlaylistEditor mPlaylistEditor;
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences; private UserPreferences mUserPreferences;
private UserPreferencesEditor mUserPreferencesEditor; private UserPreferencesEditor mUserPreferencesEditor;
@@ -91,9 +89,10 @@ public class JavaFxWindowManager extends Application
/** /**
* Constructs an instance. Note: this constructor is used for Swing applications. * Constructs an instance. Note: this constructor is used for Swing applications.
*/ */
public JavaFxWindowManager(UserPreferences userPreferences, PlaylistManager playlistManager) public JavaFxWindowManager(UserPreferences userPreferences, TunerManager tunerManager, PlaylistManager playlistManager)
{ {
mUserPreferences = userPreferences; mUserPreferences = userPreferences;
mTunerManager = tunerManager;
mPlaylistManager = playlistManager; mPlaylistManager = playlistManager;
setup(); setup();
@@ -106,12 +105,10 @@ public class JavaFxWindowManager extends Application
{ {
mUserPreferences = new UserPreferences(); mUserPreferences = new UserPreferences();
AliasModel aliasModel = new AliasModel(); AliasModel aliasModel = new AliasModel();
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel();
TunerModel tunerModel = new TunerModel(tunerConfigurationModel);
SourceManager sourceManager = new SourceManager(tunerModel, new SettingsManager(tunerConfigurationModel),
mUserPreferences);
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences); EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, sourceManager, aliasModel, eventLogManager, new IconModel()); mTunerManager = new TunerManager(mUserPreferences);
mTunerManager.start();
mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, new IconModel());
mPlaylistManager.init(); mPlaylistManager.init();
setup(); setup();
} }
@@ -274,7 +271,7 @@ public class JavaFxWindowManager extends Application
{ {
if(mPlaylistEditor == null) if(mPlaylistEditor == null)
{ {
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mUserPreferences); mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mTunerManager, mUserPreferences);
} }
return mPlaylistEditor; return mPlaylistEditor;

View File

@@ -29,6 +29,7 @@ import io.github.dsheirer.audio.playback.AudioPlaybackManager;
import io.github.dsheirer.controller.ControllerPanel; import io.github.dsheirer.controller.ControllerPanel;
import io.github.dsheirer.controller.channel.Channel; import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelAutoStartFrame; import io.github.dsheirer.controller.channel.ChannelAutoStartFrame;
import io.github.dsheirer.controller.channel.ChannelException;
import io.github.dsheirer.controller.channel.ChannelSelectionManager; import io.github.dsheirer.controller.channel.ChannelSelectionManager;
import io.github.dsheirer.eventbus.MyEventBus; import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.icon.ViewIconManagerRequest; import io.github.dsheirer.gui.icon.ViewIconManagerRequest;
@@ -47,12 +48,11 @@ import io.github.dsheirer.properties.SystemProperties;
import io.github.dsheirer.record.AudioRecordingManager; import io.github.dsheirer.record.AudioRecordingManager;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.Tuner; import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.TunerEvent; import io.github.dsheirer.source.tuner.TunerEvent;
import io.github.dsheirer.source.tuner.TunerModel; import io.github.dsheirer.source.tuner.manager.DiscoveredTuner;
import io.github.dsheirer.source.tuner.TunerSpectralDisplayManager; import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel; import io.github.dsheirer.source.tuner.ui.TunerSpectralDisplayManager;
import io.github.dsheirer.spectrum.ClearTunerMenuItem; import io.github.dsheirer.spectrum.ClearTunerMenuItem;
import io.github.dsheirer.spectrum.ShowTunerMenuItem; import io.github.dsheirer.spectrum.ShowTunerMenuItem;
import io.github.dsheirer.spectrum.SpectralDisplayPanel; import io.github.dsheirer.spectrum.SpectralDisplayPanel;
@@ -68,11 +68,25 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.MenuEvent; import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener; import javax.swing.event.MenuListener;
import javax.swing.plaf.metal.MetalLookAndFeel; import javax.swing.plaf.metal.MetalLookAndFeel;
import java.awt.*; import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
@@ -104,19 +118,24 @@ public class SDRTrunk implements Listener<TunerEvent>
private ControllerPanel mControllerPanel; private ControllerPanel mControllerPanel;
private IconModel mIconModel = new IconModel(); private IconModel mIconModel = new IconModel();
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
private SourceManager mSourceManager;
private SettingsManager mSettingsManager; private SettingsManager mSettingsManager;
private SpectralDisplayPanel mSpectralPanel; private SpectralDisplayPanel mSpectralPanel;
private JFrame mMainGui = new JFrame(); private JFrame mMainGui;
private JideSplitPane mSplitPane; private JideSplitPane mSplitPane;
private JavaFxWindowManager mJavaFxWindowManager; private JavaFxWindowManager mJavaFxWindowManager;
private UserPreferences mUserPreferences = new UserPreferences(); private UserPreferences mUserPreferences = new UserPreferences();
private TunerManager mTunerManager;
private ApplicationLog mApplicationLog; private ApplicationLog mApplicationLog;
private String mTitle; private String mTitle;
public SDRTrunk() public SDRTrunk()
{ {
if(!GraphicsEnvironment.isHeadless())
{
mMainGui = new JFrame();
}
mApplicationLog = new ApplicationLog(mUserPreferences); mApplicationLog = new ApplicationLog(mUserPreferences);
mApplicationLog.start(); mApplicationLog.start();
@@ -154,16 +173,19 @@ public class SDRTrunk implements Listener<TunerEvent>
//Register FontAwesome so we can use the fonts in Swing windows //Register FontAwesome so we can use the fonts in Swing windows
IconFontSwing.register(FontAwesome.getIconFont()); IconFontSwing.register(FontAwesome.getIconFont());
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel(); mTunerManager = new TunerManager(mUserPreferences);
TunerModel tunerModel = new TunerModel(tunerConfigurationModel); mTunerManager.start();
mSettingsManager = new SettingsManager(tunerConfigurationModel); mSettingsManager = new SettingsManager();
mSourceManager = new SourceManager(tunerModel, mSettingsManager, mUserPreferences);
AliasModel aliasModel = new AliasModel(); AliasModel aliasModel = new AliasModel();
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences); EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, mSourceManager, aliasModel, eventLogManager, mIconModel); mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, mIconModel);
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mPlaylistManager);
if(!GraphicsEnvironment.isHeadless())
{
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mTunerManager, mPlaylistManager);
}
CalibrationManager calibrationManager = CalibrationManager.getInstance(mUserPreferences); CalibrationManager calibrationManager = CalibrationManager.getInstance(mUserPreferences);
final boolean calibrating = !calibrationManager.isCalibrated() && final boolean calibrating = !calibrationManager.isCalibrated() &&
@@ -190,32 +212,45 @@ public class SDRTrunk implements Listener<TunerEvent>
MapService mapService = new MapService(mIconModel); MapService mapService = new MapService(mIconModel);
mPlaylistManager.getChannelProcessingManager().addDecodeEventListener(mapService); mPlaylistManager.getChannelProcessingManager().addDecodeEventListener(mapService);
mControllerPanel = new ControllerPanel(mPlaylistManager, audioPlaybackManager, mIconModel, mapService, if(!GraphicsEnvironment.isHeadless())
mSettingsManager, mSourceManager, mUserPreferences); {
mControllerPanel = new ControllerPanel(mPlaylistManager, audioPlaybackManager, mIconModel, mapService,
mSettingsManager, mTunerManager, mUserPreferences);
}
mSpectralPanel = new SpectralDisplayPanel(mPlaylistManager, mSettingsManager, tunerModel); mSpectralPanel = new SpectralDisplayPanel(mPlaylistManager, mSettingsManager, mTunerManager.getDiscoveredTunerModel());
TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel, TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel,
mPlaylistManager, mSettingsManager, tunerModel); mPlaylistManager, mSettingsManager, mTunerManager.getDiscoveredTunerModel());
tunerModel.addListener(tunerSpectralDisplayManager); mTunerManager.getDiscoveredTunerModel().addListener(tunerSpectralDisplayManager);
tunerModel.addListener(this); mTunerManager.getDiscoveredTunerModel().addListener(this);
mPlaylistManager.init(); mPlaylistManager.init();
mLog.info("starting main application gui"); if(GraphicsEnvironment.isHeadless())
{
mLog.info("starting main application headless");
}
else
{
mLog.info("starting main application gui");
//Initialize the GUI //Initialize the GUI
initGUI(); initGUI();
}
tunerModel.requestFirstTunerDisplay();
//Start the gui //Start the gui
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
try try
{ {
mMainGui.setVisible(true); if(!GraphicsEnvironment.isHeadless())
{
mMainGui.setVisible(true);
Tuner tuner = tunerSpectralDisplayManager.showFirstTuner();
updateTitle(tuner);
}
if(calibrating) if(calibrating && !GraphicsEnvironment.isHeadless())
{ {
Platform.runLater(() -> Platform.runLater(() ->
{ {
@@ -256,8 +291,25 @@ public class SDRTrunk implements Listener<TunerEvent>
if(channels.size() > 0) if(channels.size() > 0)
{ {
ChannelAutoStartFrame autoStartFrame = new ChannelAutoStartFrame(mPlaylistManager.getChannelProcessingManager(), if(GraphicsEnvironment.isHeadless())
channels); {
for(Channel channel: channels)
{
try
{
mLog.info("Auto-starting channel " + channel.getName());
mPlaylistManager.getChannelProcessingManager().start(channel);
}
catch(ChannelException ce)
{
mLog.error("Channel: " + channel.getName() + " auto-start failed: " + ce.getMessage());
}
}
}
else
{
new ChannelAutoStartFrame(mPlaylistManager.getChannelProcessingManager(), channels);
}
} }
} }
@@ -455,7 +507,8 @@ public class SDRTrunk implements Listener<TunerEvent>
mLog.info("Stopping spectral display ..."); mLog.info("Stopping spectral display ...");
mSpectralPanel.clearTuner(); mSpectralPanel.clearTuner();
mSourceManager.shutdown(); mLog.info("Stopping tuners ...");
mTunerManager.stop();
mLog.info("Shutdown complete."); mLog.info("Shutdown complete.");
mApplicationLog.stop(); mApplicationLog.stop();
} }
@@ -572,7 +625,23 @@ public class SDRTrunk implements Listener<TunerEvent>
{ {
if(event.getEvent() == TunerEvent.Event.REQUEST_MAIN_SPECTRAL_DISPLAY) if(event.getEvent() == TunerEvent.Event.REQUEST_MAIN_SPECTRAL_DISPLAY)
{ {
mMainGui.setTitle(mTitle + " - " + event.getTuner().getName()); updateTitle(event.getTuner());
}
}
/**
* Updates the title bar with the tuner name
* @param tuner optional
*/
private void updateTitle(Tuner tuner)
{
if(tuner != null)
{
mMainGui.setTitle(mTitle + " - " + tuner.getPreferredName());
}
else
{
mMainGui.setTitle(mTitle);
} }
} }
@@ -622,9 +691,9 @@ public class SDRTrunk implements Listener<TunerEvent>
{ {
removeAll(); removeAll();
for(Tuner tuner : mSourceManager.getTunerModel().getTuners()) for(DiscoveredTuner discoveredTuner: mTunerManager.getAvailableTuners())
{ {
add(new ShowTunerMenuItem(mSourceManager.getTunerModel(), tuner)); add(new ShowTunerMenuItem(mTunerManager.getDiscoveredTunerModel(), discoveredTuner.getTuner()));
} }
} }

View File

@@ -20,17 +20,16 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer; import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer; import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples; import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner; import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.TunerChannel; import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource; import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner; import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor; import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize; import io.github.dsheirer.spectrum.DFTSize;
@@ -40,10 +39,16 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.ArrayList; import java.util.ArrayList;
@@ -57,7 +62,7 @@ public class ChannelizerViewer extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500; private static final int CHANNEL_BANDWIDTH = 12500;
private static final int CHANNEL_FFT_FRAME_RATE = 20; private static final int CHANNEL_FFT_FRAME_RATE = 20;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel()); private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel; private JPanel mPrimaryPanel;
private JPanel mControlPanel; private JPanel mControlPanel;
private JLabel mToneFrequencyLabel; private JLabel mToneFrequencyLabel;
@@ -78,7 +83,7 @@ public class ChannelizerViewer extends JFrame
*/ */
public ChannelizerViewer(int channelsPerRow) public ChannelizerViewer(int channelsPerRow)
{ {
mTestTuner = new TestTuner(new UserPreferences()); mTestTuner = new TestTuner(new LoggingTunerErrorListener());
mChannelCount = (int)(mTestTuner.getTunerController().getBandwidth() / CHANNEL_BANDWIDTH); mChannelCount = (int)(mTestTuner.getTunerController().getBandwidth() / CHANNEL_BANDWIDTH);
mChannelsPerRow = channelsPerRow; mChannelsPerRow = channelsPerRow;
@@ -518,7 +523,7 @@ public class ChannelizerViewer extends JFrame
} }
else else
{ {
TestTuner tuner = new TestTuner(new UserPreferences()); TestTuner tuner = new TestTuner(new LoggingTunerErrorListener());
List<TunerChannel> tunerChannels = getTunerChannels(tuner); List<TunerChannel> tunerChannels = getTunerChannels(tuner);

View File

@@ -20,18 +20,17 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer; import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer; import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples; import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner; import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification; import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel; import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource; import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner; import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor; import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize; import io.github.dsheirer.spectrum.DFTSize;
@@ -41,10 +40,18 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.ArrayList; import java.util.ArrayList;
@@ -56,7 +63,7 @@ public class ChannelizerViewer2 extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500; private static final int CHANNEL_BANDWIDTH = 12500;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel()); private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel; private JPanel mPrimaryPanel;
private JPanel mControlPanel; private JPanel mControlPanel;
private JButton mTopFrameAddChannelButton; private JButton mTopFrameAddChannelButton;
@@ -68,7 +75,7 @@ public class ChannelizerViewer2 extends JFrame
private ChannelArrayPanel mBottomChannelArrayPanel; private ChannelArrayPanel mBottomChannelArrayPanel;
private DFTSize mMainPanelDFTSize = DFTSize.FFT32768; private DFTSize mMainPanelDFTSize = DFTSize.FFT32768;
private DFTSize mChannelPanelDFTSize = DFTSize.FFT04096; private DFTSize mChannelPanelDFTSize = DFTSize.FFT04096;
private TestTuner mTestTuner = new TestTuner(new UserPreferences()); private TestTuner mTestTuner = new TestTuner(new LoggingTunerErrorListener());
/** /**
* GUI Test utility for researching polyphase channelizers. * GUI Test utility for researching polyphase channelizers.

View File

@@ -20,18 +20,17 @@ package io.github.dsheirer.gui.channelizer;
import io.github.dsheirer.buffer.FloatNativeBuffer; import io.github.dsheirer.buffer.FloatNativeBuffer;
import io.github.dsheirer.buffer.INativeBuffer; import io.github.dsheirer.buffer.INativeBuffer;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples; import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.ISourceEventProcessor;
import io.github.dsheirer.source.SourceEvent; import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException; import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.tuner.LoggingTunerErrorListener;
import io.github.dsheirer.source.tuner.Tuner; import io.github.dsheirer.source.tuner.Tuner;
import io.github.dsheirer.source.tuner.channel.ChannelSpecification; import io.github.dsheirer.source.tuner.channel.ChannelSpecification;
import io.github.dsheirer.source.tuner.channel.TunerChannel; import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.TunerChannelSource; import io.github.dsheirer.source.tuner.channel.TunerChannelSource;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.source.tuner.test.TestTuner; import io.github.dsheirer.source.tuner.test.TestTuner;
import io.github.dsheirer.spectrum.ComplexDftProcessor; import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize; import io.github.dsheirer.spectrum.DFTSize;
@@ -41,10 +40,16 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JToggleButton;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.util.ArrayList; import java.util.ArrayList;
@@ -58,7 +63,7 @@ public class HeterodyneChannelizerViewer extends JFrame
private static final int CHANNEL_BANDWIDTH = 12500; private static final int CHANNEL_BANDWIDTH = 12500;
private static final int CHANNEL_FFT_FRAME_RATE = 20; private static final int CHANNEL_FFT_FRAME_RATE = 20;
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel()); private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel; private JPanel mPrimaryPanel;
private JPanel mControlPanel; private JPanel mControlPanel;
private JLabel mToneFrequencyLabel; private JLabel mToneFrequencyLabel;
@@ -77,7 +82,7 @@ public class HeterodyneChannelizerViewer extends JFrame
*/ */
public HeterodyneChannelizerViewer() public HeterodyneChannelizerViewer()
{ {
mTestTuner = new TestTuner(new UserPreferences()); mTestTuner = new TestTuner(new LoggingTunerErrorListener());
mChannelCount = 5; mChannelCount = 5;
mChannelsPerRow = 5; mChannelsPerRow = 5;
init(); init();
@@ -516,7 +521,7 @@ public class HeterodyneChannelizerViewer extends JFrame
} }
else else
{ {
TestTuner tuner = new TestTuner(new UserPreferences()); TestTuner tuner = new TestTuner(new LoggingTunerErrorListener());
List<TunerChannel> tunerChannels = getTunerChannels(tuner); List<TunerChannel> tunerChannels = getTunerChannels(tuner);

View File

@@ -29,7 +29,6 @@ import io.github.dsheirer.dsp.oscillator.OscillatorFactory;
import io.github.dsheirer.sample.Listener; import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.complex.ComplexSamples; import io.github.dsheirer.sample.complex.ComplexSamples;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.settings.SettingsManager;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import io.github.dsheirer.spectrum.ComplexDftProcessor; import io.github.dsheirer.spectrum.ComplexDftProcessor;
import io.github.dsheirer.spectrum.DFTSize; import io.github.dsheirer.spectrum.DFTSize;
import io.github.dsheirer.spectrum.SpectrumPanel; import io.github.dsheirer.spectrum.SpectrumPanel;
@@ -39,10 +38,15 @@ import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.swing.*; import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import java.awt.*; import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class SynthesizerViewer extends JFrame public class SynthesizerViewer extends JFrame
@@ -54,7 +58,7 @@ public class SynthesizerViewer extends JFrame
private static final int CHANNEL_FFT_FRAME_RATE = 20; //frames per second private static final int CHANNEL_FFT_FRAME_RATE = 20; //frames per second
private static final int DATA_GENERATOR_FRAME_RATE = 50; //frames per second private static final int DATA_GENERATOR_FRAME_RATE = 50; //frames per second
private SettingsManager mSettingsManager = new SettingsManager(new TunerConfigurationModel()); private SettingsManager mSettingsManager = new SettingsManager();
private JPanel mPrimaryPanel; private JPanel mPrimaryPanel;
private PrimarySpectrumPanel mPrimarySpectrumPanel; private PrimarySpectrumPanel mPrimarySpectrumPanel;
private ChannelPanel mChannel1Panel; private ChannelPanel mChannel1Panel;

View File

@@ -1,6 +1,6 @@
/******************************************************************************* /*
* sdrtrunk * *****************************************************************************
* Copyright (C) 2014-2017 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -14,7 +14,8 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/ * ****************************************************************************
*/
package io.github.dsheirer.gui.control; package io.github.dsheirer.gui.control;
import io.github.dsheirer.source.ISourceEventProcessor; import io.github.dsheirer.source.ISourceEventProcessor;
@@ -69,12 +70,6 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
init(); init();
} }
public JFrequencyControl(long value)
{
this();
mFrequency = value;
}
private void init() private void init()
{ {
setLayout(new MigLayout("insets 0 0 0 0", "[]0[]", "")); setLayout(new MigLayout("insets 0 0 0 0", "[]0[]", ""));
@@ -91,8 +86,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
} }
catch(ParseException e) catch(ParseException e)
{ {
mLog.error("JFrequencyControl - parse exception " mLog.error("JFrequencyControl - parse exception constructing a digit - " + e);
+ "constructing a digit - " + e);
} }
if(digit != null) if(digit != null)
@@ -105,15 +99,11 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
if(x == 6) if(x == 6)
{ {
JLabel period = new JLabel("."); add(new JLabel(". "));
add(period);
} }
} }
} }
add(new JLabel(" MHz"));
/** /**
* Create a blank cursor to use when the mouse is over the digits * Create a blank cursor to use when the mouse is over the digits
*/ */
@@ -123,11 +113,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
//Create image for cursor using empty array //Create image for cursor using empty array
Image cursorImage = Toolkit.getDefaultToolkit().createImage(imageByte); Image cursorImage = Toolkit.getDefaultToolkit().createImage(imageByte);
mBlankCursor = Toolkit.getDefaultToolkit() mBlankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImage, new Point(0, 0), "cursor");
.createCustomCursor(cursorImage, new Point(0, 0), "cursor");
setTooltip(false);
revalidate(); revalidate();
} }
@@ -142,26 +128,6 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
} }
} }
private void setTooltip(boolean locked)
{
String tooltip = null;
if(locked)
{
tooltip = "Frequency control is locked. Disable decoding channels to unlock.";
}
else
{
tooltip = "Click on a frequency digit and type a frequency value, or click the upper/lower digits to " +
"change the value";
}
for(Digit digit: mDigits.values())
{
digit.setToolTipText(tooltip);
}
}
/** /**
* Receives a frequency change event invoked by another control. We don't * Receives a frequency change event invoked by another control. We don't
* rebroadcast this event, just set the control to indicate the new frequency. * rebroadcast this event, just set the control to indicate the new frequency.
@@ -172,36 +138,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
switch(event.getEvent()) switch(event.getEvent())
{ {
case NOTIFICATION_FREQUENCY_CHANGE: case NOTIFICATION_FREQUENCY_CHANGE:
EventQueue.invokeLater(new Runnable() EventQueue.invokeLater(() -> setFrequency(event.getValue().longValue(), false));
{
@Override
public void run()
{
setFrequency(event.getValue().longValue(), false);
}
});
break;
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_LOCKED:
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
setEnabled(false);
setTooltip(true);
}
});
break;
case NOTIFICATION_FREQUENCY_AND_SAMPLE_RATE_UNLOCKED:
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
setEnabled(true);
setTooltip(false);
}
});
break; break;
} }
} }
@@ -251,11 +188,30 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
} }
} }
/**
* Adds the source event listener
* @param processor
*/
public void addListener(ISourceEventProcessor processor) public void addListener(ISourceEventProcessor processor)
{ {
mProcessors.add(processor); if(!mProcessors.contains(processor))
{
mProcessors.add(processor);
}
} }
/**
* Remove all source event processors
*/
public void clearListeners()
{
mProcessors.clear();
}
/**
* Removes the source event processor
* @param processor
*/
public void removeListener(ISourceEventProcessor processor) public void removeListener(ISourceEventProcessor processor)
{ {
mProcessors.remove(processor); mProcessors.remove(processor);
@@ -272,7 +228,7 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
super("0"); super("0");
mPower = position; mPower = position;
setToolTipText(getTooltip(mPower));
Listener listener = new Listener(); Listener listener = new Listener();
this.addKeyListener(listener); this.addKeyListener(listener);
@@ -280,6 +236,49 @@ public class JFrequencyControl extends JPanel implements ISourceEventProcessor
this.addMouseWheelListener(listener); this.addMouseWheelListener(listener);
} }
private static String getTooltip(int power)
{
StringBuilder sb = new StringBuilder();
sb.append("Center frequency ");
switch(power)
{
case 0:
sb.append("1 Hertz");
break;
case 1:
sb.append("10 Hertz");
break;
case 2:
sb.append("100 Hertz");
break;
case 3:
sb.append("1 Kilohertz");
break;
case 4:
sb.append("10 Kilohertz");
break;
case 5:
sb.append("100 Kilohertz");
break;
case 6:
sb.append("1 Megahertz");
break;
case 7:
sb.append("10 Megahertz");
break;
case 8:
sb.append("100 Megahertz");
break;
case 9:
sb.append("1 Gigahertz");
break;
}
sb.append(" units. Type a number, use up/down arrows, or click the upper/lower digit control to adjust");
return sb.toString();
}
/** /**
* Sets this digit to the value of the column in frequency that corresponds * Sets this digit to the value of the column in frequency that corresponds
* to the power (ie column) set for this digit. Optionally, fires a * to the power (ie column) set for this digit. Optionally, fires a

View File

@@ -1,31 +0,0 @@
package io.github.dsheirer.gui.editor;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
public class EmptyEditor<T> extends Editor<T>
{
private static final long serialVersionUID = 1L;
public EmptyEditor( String descriptor )
{
setLayout( new MigLayout( "insets 0 0 0 0", "[center]", "[grow]" ) );
add( new JLabel( "Please select " + descriptor ), "wrap" );
}
public EmptyEditor()
{
this( "an item" );
}
@Override
public void save()
{
}
@Override
public void reset()
{
}
}

View File

@@ -1,7 +1,6 @@
/* /*
* ****************************************************************************** * *****************************************************************************
* sdrtrunk * Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2019 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* ***************************************************************************** * ****************************************************************************
*/ */
package io.github.dsheirer.gui.instrument.decoder; package io.github.dsheirer.gui.instrument.decoder;

View File

@@ -32,6 +32,7 @@ import io.github.dsheirer.gui.preference.PreferenceEditorType;
import io.github.dsheirer.gui.preference.ViewUserPreferenceEditorRequest; import io.github.dsheirer.gui.preference.ViewUserPreferenceEditorRequest;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import io.github.dsheirer.util.TimeStamp; import io.github.dsheirer.util.TimeStamp;
import javafx.application.Platform; import javafx.application.Platform;
@@ -65,6 +66,7 @@ public class PlaylistEditor extends BorderPane
private static final Logger mLog = LoggerFactory.getLogger(PlaylistEditor.class); private static final Logger mLog = LoggerFactory.getLogger(PlaylistEditor.class);
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences; private UserPreferences mUserPreferences;
private MenuBar mMenuBar; private MenuBar mMenuBar;
private TabPane mTabPane; private TabPane mTabPane;
@@ -79,11 +81,13 @@ public class PlaylistEditor extends BorderPane
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager for alias and channel models * @param playlistManager for alias and channel models
* @param tunerManager for tuners
* @param userPreferences for settings * @param userPreferences for settings
*/ */
public PlaylistEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public PlaylistEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{ {
mPlaylistManager = playlistManager; mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences; mUserPreferences = userPreferences;
//Throw a new runnable back onto the FX thread to lazy load the editor content after the editor has been //Throw a new runnable back onto the FX thread to lazy load the editor content after the editor has been
@@ -240,7 +244,7 @@ public class PlaylistEditor extends BorderPane
{ {
if(mChannelEditor == null) if(mChannelEditor == null)
{ {
mChannelEditor = new ChannelEditor(mPlaylistManager, mUserPreferences); mChannelEditor = new ChannelEditor(mPlaylistManager, mTunerManager, mUserPreferences);
} }
return mChannelEditor; return mChannelEditor;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -20,17 +20,12 @@
package io.github.dsheirer.gui.playlist; package io.github.dsheirer.gui.playlist;
import io.github.dsheirer.alias.AliasModel; import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.gui.JavaFxWindowManager; import io.github.dsheirer.gui.JavaFxWindowManager;
import io.github.dsheirer.icon.IconModel; import io.github.dsheirer.icon.IconModel;
import io.github.dsheirer.module.log.EventLogManager; import io.github.dsheirer.module.log.EventLogManager;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.settings.SettingsManager; import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.configuration.TunerConfigurationModel;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.Scene; import javafx.scene.Scene;
@@ -43,6 +38,7 @@ public class PlaylistEditorApplication extends Application
{ {
private Stage mStage; private Stage mStage;
private Parent mPlaylistEditor; private Parent mPlaylistEditor;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences = new UserPreferences(); private UserPreferences mUserPreferences = new UserPreferences();
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
private JavaFxWindowManager mJavaFxWindowManager; private JavaFxWindowManager mJavaFxWindowManager;
@@ -50,17 +46,13 @@ public class PlaylistEditorApplication extends Application
public PlaylistEditorApplication() public PlaylistEditorApplication()
{ {
AliasModel aliasModel = new AliasModel(); AliasModel aliasModel = new AliasModel();
BroadcastModel broadcastModel = new BroadcastModel(aliasModel, new IconModel(), mUserPreferences);
ChannelMapModel channelMapModel = new ChannelMapModel();
TunerConfigurationModel tunerConfigurationModel = new TunerConfigurationModel();
TunerModel tunerModel = new TunerModel(tunerConfigurationModel);
SourceManager sourceManager = new SourceManager(tunerModel, new SettingsManager(tunerConfigurationModel),
mUserPreferences);
EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences); EventLogManager eventLogManager = new EventLogManager(aliasModel, mUserPreferences);
mPlaylistManager = new PlaylistManager(mUserPreferences, sourceManager, aliasModel, eventLogManager, new IconModel()); mTunerManager = new TunerManager(mUserPreferences);
mTunerManager.start();
mPlaylistManager = new PlaylistManager(mUserPreferences, mTunerManager, aliasModel, eventLogManager, new IconModel());
mPlaylistManager.init(); mPlaylistManager.init();
mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mPlaylistManager); mJavaFxWindowManager = new JavaFxWindowManager(mUserPreferences, mTunerManager, mPlaylistManager);
} }
@Override @Override
@@ -77,7 +69,7 @@ public class PlaylistEditorApplication extends Application
{ {
if(mPlaylistEditor == null) if(mPlaylistEditor == null)
{ {
mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mUserPreferences); mPlaylistEditor = new PlaylistEditor(mPlaylistManager, mTunerManager, mUserPreferences);
} }
return mPlaylistEditor; return mPlaylistEditor;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -34,6 +31,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -59,11 +57,14 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public AMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public AMConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getRecordPane()); getTitledPanesBox().getChildren().add(getRecordPane());
@@ -138,7 +139,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -36,7 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfigTuner; import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.TunerModel; import io.github.dsheirer.source.tuner.manager.TunerManager;
import io.github.dsheirer.util.ThreadPool; import io.github.dsheirer.util.ThreadPool;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@@ -80,6 +80,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
private final static Logger mLog = LoggerFactory.getLogger(ChannelConfigurationEditor.class); private final static Logger mLog = LoggerFactory.getLogger(ChannelConfigurationEditor.class);
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
protected TunerManager mTunerManager;
protected UserPreferences mUserPreferences; protected UserPreferences mUserPreferences;
protected EditorModificationListener mEditorModificationListener = new EditorModificationListener(); protected EditorModificationListener mEditorModificationListener = new EditorModificationListener();
private Button mPlayButton; private Button mPlayButton;
@@ -100,9 +101,17 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
private IconNode mStopGraphicNode; private IconNode mStopGraphicNode;
private ChannelProcessingMonitor mChannelProcessingMonitor = new ChannelProcessingMonitor(); private ChannelProcessingMonitor mChannelProcessingMonitor = new ChannelProcessingMonitor();
public ChannelConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) /**
* Constructs an instance
* @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/
public ChannelConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
mPlaylistManager = playlistManager; mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences; mUserPreferences = userPreferences;
setMaxWidth(Double.MAX_VALUE); setMaxWidth(Double.MAX_VALUE);
@@ -236,11 +245,6 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
modifiedProperty().setValue(false); modifiedProperty().setValue(false);
} }
protected TunerModel getTunerModel()
{
return mPlaylistManager.getTunerModel();
}
@Override @Override
public void save() public void save()
{ {

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -25,6 +22,7 @@ package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -46,28 +44,28 @@ public class ChannelConfigurationEditorFactory
* @return constructed editor * @return constructed editor
*/ */
public static ChannelConfigurationEditor getEditor(DecoderType decoderType, PlaylistManager playlistManager, public static ChannelConfigurationEditor getEditor(DecoderType decoderType, PlaylistManager playlistManager,
UserPreferences userPreferences) TunerManager tunerManager, UserPreferences userPreferences)
{ {
switch(decoderType) switch(decoderType)
{ {
case AM: case AM:
return new AMConfigurationEditor(playlistManager, userPreferences); return new AMConfigurationEditor(playlistManager, tunerManager, userPreferences);
case DMR: case DMR:
return new DMRConfigurationEditor(playlistManager, userPreferences); return new DMRConfigurationEditor(playlistManager, tunerManager, userPreferences);
case NBFM: case NBFM:
return new NBFMConfigurationEditor(playlistManager, userPreferences); return new NBFMConfigurationEditor(playlistManager, tunerManager, userPreferences);
case LTR_NET: case LTR_NET:
return new LTRNetConfigurationEditor(playlistManager, userPreferences); return new LTRNetConfigurationEditor(playlistManager, tunerManager, userPreferences);
case LTR: case LTR:
return new LTRConfigurationEditor(playlistManager, userPreferences); return new LTRConfigurationEditor(playlistManager, tunerManager, userPreferences);
case MPT1327: case MPT1327:
return new MPT1327ConfigurationEditor(playlistManager, userPreferences); return new MPT1327ConfigurationEditor(playlistManager, tunerManager, userPreferences);
case PASSPORT: case PASSPORT:
return new PassportConfigurationEditor(playlistManager, userPreferences); return new PassportConfigurationEditor(playlistManager, tunerManager, userPreferences);
case P25_PHASE1: case P25_PHASE1:
return new P25P1ConfigurationEditor(playlistManager, userPreferences); return new P25P1ConfigurationEditor(playlistManager, tunerManager, userPreferences);
case P25_PHASE2: case P25_PHASE2:
return new P25P2ConfigurationEditor(playlistManager, userPreferences); return new P25P2ConfigurationEditor(playlistManager, tunerManager, userPreferences);
default: default:
if(decoderType != null && !mLoggedUnrecognizedTypes.contains(decoderType)) if(decoderType != null && !mLoggedUnrecognizedTypes.contains(decoderType))
{ {

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -28,6 +25,7 @@ import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.playlist.PlaylistManager; import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@@ -79,6 +77,7 @@ public class ChannelEditor extends SplitPane
{ {
private final static Logger mLog = LoggerFactory.getLogger(ChannelEditor.class); private final static Logger mLog = LoggerFactory.getLogger(ChannelEditor.class);
private PlaylistManager mPlaylistManager; private PlaylistManager mPlaylistManager;
private TunerManager mTunerManager;
private UserPreferences mUserPreferences; private UserPreferences mUserPreferences;
private TableView<Channel> mChannelTableView; private TableView<Channel> mChannelTableView;
private Label mPlaceholderLabel; private Label mPlaceholderLabel;
@@ -102,11 +101,12 @@ public class ChannelEditor extends SplitPane
* Constructs an instance * Constructs an instance
* @param playlistManager containing playlists and channel configurations * @param playlistManager containing playlists and channel configurations
*/ */
public ChannelEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public ChannelEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{ {
mPlaylistManager = playlistManager; mPlaylistManager = playlistManager;
mTunerManager = tunerManager;
mUserPreferences = userPreferences; mUserPreferences = userPreferences;
mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager, userPreferences); mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager, mTunerManager, userPreferences);
HBox channelsBox = new HBox(); HBox channelsBox = new HBox();
channelsBox.setSpacing(10.0); channelsBox.setSpacing(10.0);
@@ -203,7 +203,7 @@ public class ChannelEditor extends SplitPane
if(editor == null) if(editor == null)
{ {
editor = ChannelConfigurationEditorFactory.getEditor(channelDecoderType, mPlaylistManager, editor = ChannelConfigurationEditorFactory.getEditor(channelDecoderType, mPlaylistManager,
mUserPreferences); mTunerManager, mUserPreferences);
if(editor != null) if(editor != null)
{ {

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -40,6 +37,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
@@ -96,11 +94,14 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public DMRConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public DMRConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane()); getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -240,7 +241,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(), mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MINIMUM_MS, DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MAXIMUM_MS, DecodeConfigDMR.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigDMR.CHANNEL_ROTATION_DELAY_DEFAULT_MS); DecodeConfigDMR.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -74,12 +72,14 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param userPreferences * @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public LTRConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public LTRConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane()); getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -210,7 +210,7 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -74,12 +72,13 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param userPreferences * @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public LTRNetConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public LTRNetConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager, UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane()); getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -210,7 +209,7 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -40,6 +37,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.geometry.HPos; import javafx.geometry.HPos;
@@ -84,12 +82,14 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param userPreferences * @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public MPT1327ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public MPT1327ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane()); getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -195,7 +195,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(), mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MINIMUM_MS, DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MAXIMUM_MS, DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_DEFAULT_MS); DecodeConfigMPT1327.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -42,6 +39,7 @@ import io.github.dsheirer.protocol.Protocol;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
@@ -92,12 +90,14 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param userPreferences * @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public NBFMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public NBFMConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane()); getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -228,7 +228,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -38,6 +35,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos; import javafx.geometry.HPos;
@@ -80,12 +78,14 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
/** /**
* Constructs an instance * Constructs an instance
* @param playlistManager * @param playlistManager for playlists
* @param userPreferences * @param tunerManager for tuners
* @param userPreferences for preferences
*/ */
public P25P1ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public P25P1ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane()); getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -191,7 +191,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel(), mSourceConfigurationEditor = new FrequencyEditor(mTunerManager,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MINIMUM_MS, DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MINIMUM_MS,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MAXIMUM_MS, DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_MAXIMUM_MS,
DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_DEFAULT_MS); DecodeConfigP25Phase1.CHANNEL_ROTATION_DELAY_DEFAULT_MS);

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -39,6 +36,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.HPos; import javafx.geometry.HPos;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
@@ -73,9 +71,10 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
* @param playlistManager * @param playlistManager
* @param userPreferences * @param userPreferences
*/ */
public P25P2ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public P25P2ConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getEventLogPane()); getTitledPanesBox().getChildren().add(getEventLogPane());
@@ -179,7 +178,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -38,6 +35,7 @@ import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.RecorderType; import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TitledPane; import javafx.scene.control.TitledPane;
@@ -69,9 +67,10 @@ public class PassportConfigurationEditor extends ChannelConfigurationEditor
* @param playlistManager * @param playlistManager
* @param userPreferences * @param userPreferences
*/ */
public PassportConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public PassportConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getSourcePane()); getTitledPanesBox().getChildren().add(getSourcePane());
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
getTitledPanesBox().getChildren().add(getAuxDecoderPane()); getTitledPanesBox().getChildren().add(getAuxDecoderPane());
@@ -155,7 +154,7 @@ public class PassportConfigurationEditor extends ChannelConfigurationEditor
{ {
if(mSourceConfigurationEditor == null) if(mSourceConfigurationEditor == null)
{ {
mSourceConfigurationEditor = new FrequencyEditor(getTunerModel()); mSourceConfigurationEditor = new FrequencyEditor(mTunerManager);
//Add a listener so that we can push change notifications up to this editor //Add a listener so that we can push change notifications up to this editor
mSourceConfigurationEditor.modifiedProperty() mSourceConfigurationEditor.modifiedProperty()

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.channel; package io.github.dsheirer.gui.playlist.channel;
@@ -30,6 +27,7 @@ import io.github.dsheirer.playlist.PlaylistManager;
import io.github.dsheirer.preference.UserPreferences; import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.config.RecordConfiguration; import io.github.dsheirer.record.config.RecordConfiguration;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.scene.control.TitledPane; import javafx.scene.control.TitledPane;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -46,9 +44,10 @@ public class UnknownConfigurationEditor extends ChannelConfigurationEditor
* Constructs an instance * Constructs an instance
* @param aliasModel * @param aliasModel
*/ */
public UnknownConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences) public UnknownConfigurationEditor(PlaylistManager playlistManager, TunerManager tunerManager,
UserPreferences userPreferences)
{ {
super(playlistManager, userPreferences); super(playlistManager, tunerManager, userPreferences);
getTitledPanesBox().getChildren().add(getDecoderPane()); getTitledPanesBox().getChildren().add(getDecoderPane());
} }

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.source; package io.github.dsheirer.gui.playlist.source;
@@ -25,8 +22,8 @@ package io.github.dsheirer.gui.playlist.source;
import io.github.dsheirer.source.config.SourceConfigTuner; import io.github.dsheirer.source.config.SourceConfigTuner;
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency; import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
import io.github.dsheirer.source.config.SourceConfiguration; import io.github.dsheirer.source.config.SourceConfiguration;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.channel.rotation.ChannelRotationMonitor; import io.github.dsheirer.source.tuner.channel.rotation.ChannelRotationMonitor;
import io.github.dsheirer.source.tuner.manager.TunerManager;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
@@ -59,7 +56,7 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
{ {
private final static Logger mLog = LoggerFactory.getLogger(FrequencyEditor.class); private final static Logger mLog = LoggerFactory.getLogger(FrequencyEditor.class);
private static final String NONE = "(none) "; private static final String NONE = "(none) ";
private TunerModel mTunerModel; private TunerManager mTunerManager;
private FrequencyBox mPrimaryFrequencyBox; private FrequencyBox mPrimaryFrequencyBox;
private ObservableList<FrequencyBox> mFrequencyBoxes = FXCollections.observableArrayList(); private ObservableList<FrequencyBox> mFrequencyBoxes = FXCollections.observableArrayList();
private ComboBox<String> mPreferredTunerComboBox; private ComboBox<String> mPreferredTunerComboBox;
@@ -75,13 +72,13 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
* define constraints for the channel rotation delay monitor, how long the monitor dwells on each frequency in a * define constraints for the channel rotation delay monitor, how long the monitor dwells on each frequency in a
* multi-frequency configuration. * multi-frequency configuration.
* *
* @param tunerModel for accessing list of tuners to select a preferred tuner * @param tunerManager for accessing list of tuners to select a preferred tuner
* @param minRotationDelay in milliseconds for channel/frequency dwell * @param minRotationDelay in milliseconds for channel/frequency dwell
* @param maxRotationDelay in milliseconds for channel/frequency dwell * @param maxRotationDelay in milliseconds for channel/frequency dwell
*/ */
public FrequencyEditor(TunerModel tunerModel, int minRotationDelay, int maxRotationDelay, int defaultRotationDelay) public FrequencyEditor(TunerManager tunerManager, int minRotationDelay, int maxRotationDelay, int defaultRotationDelay)
{ {
mTunerModel = tunerModel; mTunerManager = tunerManager;
mAllowMultipleFrequencies = true; mAllowMultipleFrequencies = true;
mFrequencyRotationMinimum = minRotationDelay; mFrequencyRotationMinimum = minRotationDelay;
mFrequencyRotationMaximum = maxRotationDelay; mFrequencyRotationMaximum = maxRotationDelay;
@@ -91,11 +88,11 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
/** /**
* Constructs an instance with a default behavior of single frequency support only. * Constructs an instance with a default behavior of single frequency support only.
* @param tunerModel for accessing list of tuners to select a preferred tuner * @param tunerManager for accessing list of tuners to select a preferred tuner
*/ */
public FrequencyEditor(TunerModel tunerModel) public FrequencyEditor(TunerManager tunerManager)
{ {
mTunerModel = tunerModel; mTunerManager = tunerManager;
init(); init();
} }
@@ -333,9 +330,9 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
getPreferredTunerComboBox().getItems().clear(); getPreferredTunerComboBox().getItems().clear();
getPreferredTunerComboBox().getItems().add(NONE); getPreferredTunerComboBox().getItems().add(NONE);
if(mTunerModel != null) if(mTunerManager != null)
{ {
getPreferredTunerComboBox().getItems().addAll(mTunerModel.getTunerNames()); getPreferredTunerComboBox().getItems().addAll(mTunerManager.getPreferredTunerNames());
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -34,6 +34,7 @@ import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.controlsfx.control.ToggleSwitch;
/** /**
* Broadcastify calls API configuration editor * Broadcastify calls API configuration editor
@@ -47,6 +48,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
private TextField mApiKeyTextField; private TextField mApiKeyTextField;
private TextField mHostTextField; private TextField mHostTextField;
private GridPane mEditorPane; private GridPane mEditorPane;
private ToggleSwitch mTestEnabledToggleSwitch;
private IntegerTextField mTestIntervalTextField;
/** /**
* Constructs an instance * Constructs an instance
@@ -66,6 +69,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setDisable(item == null); getApiKeyTextField().setDisable(item == null);
getHostTextField().setDisable(item == null); getHostTextField().setDisable(item == null);
getMaxAgeTextField().setDisable(item == null); getMaxAgeTextField().setDisable(item == null);
getTestEnabledToggleSwitch().setDisable(item == null);
getTestIntervalTextField().setDisable(item == null);
if(item != null) if(item != null)
{ {
@@ -73,6 +78,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setText(item.getApiKey()); getApiKeyTextField().setText(item.getApiKey());
getHostTextField().setText(item.getHost()); getHostTextField().setText(item.getHost());
getMaxAgeTextField().set((int)(item.getMaximumRecordingAge() / 1000)); getMaxAgeTextField().set((int)(item.getMaximumRecordingAge() / 1000));
getTestEnabledToggleSwitch().setSelected(item.isTestEnabled());
getTestIntervalTextField().set(item.getTestInterval());
} }
else else
{ {
@@ -80,6 +87,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getApiKeyTextField().setText(null); getApiKeyTextField().setText(null);
getHostTextField().setText(null); getHostTextField().setText(null);
getMaxAgeTextField().set(0); getMaxAgeTextField().set(0);
getTestEnabledToggleSwitch().setSelected(false);
getTestIntervalTextField().set(15);
} }
modifiedProperty().set(false); modifiedProperty().set(false);
@@ -100,6 +109,8 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
getItem().setHost(getHostTextField().getText()); getItem().setHost(getHostTextField().getText());
getItem().setApiKey(getApiKeyTextField().getText()); getItem().setApiKey(getApiKeyTextField().getText());
getItem().setMaximumRecordingAge(getMaxAgeTextField().get() * 1000); getItem().setMaximumRecordingAge(getMaxAgeTextField().get() * 1000);
getItem().setTestEnabled(getTestEnabledToggleSwitch().isSelected());
getItem().setTestInterval(getTestIntervalTextField().get());
} }
super.save(); super.save();
@@ -177,6 +188,22 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
GridPane.setConstraints(getMaxAgeTextField(), 1, row); GridPane.setConstraints(getMaxAgeTextField(), 1, row);
mEditorPane.getChildren().add(getMaxAgeTextField()); mEditorPane.getChildren().add(getMaxAgeTextField());
Label testEnabledLabel = new Label("Send Periodic Keep-Alive");
GridPane.setHalignment(testEnabledLabel, HPos.RIGHT);
GridPane.setConstraints(testEnabledLabel, 0, ++row);
mEditorPane.getChildren().add(testEnabledLabel);
GridPane.setConstraints(getTestEnabledToggleSwitch(), 1, row);
mEditorPane.getChildren().add(getTestEnabledToggleSwitch());
Label testIntervalLabel = new Label("Ping Interval (minutes)");
GridPane.setHalignment(testIntervalLabel, HPos.RIGHT);
GridPane.setConstraints(testIntervalLabel, 3, row);
mEditorPane.getChildren().add(testIntervalLabel);
GridPane.setConstraints(getTestIntervalTextField(), 4, row);
mEditorPane.getChildren().add(getTestIntervalTextField());
GridPane.setConstraints(getTestButton(), 1, ++row); GridPane.setConstraints(getTestButton(), 1, ++row);
mEditorPane.getChildren().add(getTestButton()); mEditorPane.getChildren().add(getTestButton());
} }
@@ -232,6 +259,31 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
return mSystemIdTextField; return mSystemIdTextField;
} }
private ToggleSwitch getTestEnabledToggleSwitch()
{
if(mTestEnabledToggleSwitch == null)
{
mTestEnabledToggleSwitch = new ToggleSwitch();
mTestEnabledToggleSwitch.setDisable(true);
mTestEnabledToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
return mTestEnabledToggleSwitch;
}
private IntegerTextField getTestIntervalTextField()
{
if(mTestIntervalTextField == null)
{
mTestIntervalTextField = new IntegerTextField();
mTestIntervalTextField.setDisable(true);
mTestIntervalTextField.textProperty().addListener(mEditorModificationListener);
}
return mTestIntervalTextField;
}
private Button getTestButton() private Button getTestButton()
{ {
if(mTestButton == null) if(mTestButton == null)

View File

@@ -30,6 +30,7 @@ import javafx.geometry.Insets;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane; import javafx.scene.layout.GridPane;
import org.controlsfx.control.ToggleSwitch;
/** /**
* Icecast streaming configuration editor * Icecast streaming configuration editor
@@ -37,6 +38,7 @@ import javafx.scene.layout.GridPane;
public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastConfiguration> public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastConfiguration>
{ {
private GridPane mEditorPane; private GridPane mEditorPane;
private ToggleSwitch mInlineToggleSwitch;
private TextField mMountPointTextField; private TextField mMountPointTextField;
private TextField mUserNameTextField; private TextField mUserNameTextField;
private TextField mDescriptionTextField; private TextField mDescriptionTextField;
@@ -52,6 +54,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
public void setItem(IcecastConfiguration item) public void setItem(IcecastConfiguration item)
{ {
getMountPointTextField().setDisable(item == null); getMountPointTextField().setDisable(item == null);
getInlineToggleSwitch().setDisable(item == null);
getUserNameTextField().setDisable(item == null); getUserNameTextField().setDisable(item == null);
getDescriptionTextField().setDisable(item == null); getDescriptionTextField().setDisable(item == null);
getGenreTextField().setDisable(item == null); getGenreTextField().setDisable(item == null);
@@ -60,6 +63,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
if(item != null) if(item != null)
{ {
getMountPointTextField().setText(item.getMountPoint()); getMountPointTextField().setText(item.getMountPoint());
getInlineToggleSwitch().setSelected(item.getInline());
getUserNameTextField().setText(item.getUserName()); getUserNameTextField().setText(item.getUserName());
getDescriptionTextField().setText(item.getDescription()); getDescriptionTextField().setText(item.getDescription());
getGenreTextField().setText(item.getGenre()); getGenreTextField().setText(item.getGenre());
@@ -68,6 +72,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
else else
{ {
getMountPointTextField().setText(null); getMountPointTextField().setText(null);
getInlineToggleSwitch().setSelected(false);
getUserNameTextField().setText(null); getUserNameTextField().setText(null);
getDescriptionTextField().setText(null); getDescriptionTextField().setText(null);
getGenreTextField().setText(null); getGenreTextField().setText(null);
@@ -83,6 +88,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
if(getItem() != null) if(getItem() != null)
{ {
getItem().setMountPoint(getMountPointTextField().getText()); getItem().setMountPoint(getMountPointTextField().getText());
getItem().setInline(getInlineToggleSwitch().isSelected());
getItem().setUserName(getUserNameTextField().getText()); getItem().setUserName(getUserNameTextField().getText());
getItem().setDescription(getDescriptionTextField().getText()); getItem().setDescription(getDescriptionTextField().getText());
getItem().setGenre(getGenreTextField().getText()); getItem().setGenre(getGenreTextField().getText());
@@ -150,6 +156,14 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
GridPane.setConstraints(getMountPointTextField(), 1, 3); GridPane.setConstraints(getMountPointTextField(), 1, 3);
mEditorPane.getChildren().add(getMountPointTextField()); mEditorPane.getChildren().add(getMountPointTextField());
Label inlineLabel = new Label("Inline Metadata");
GridPane.setHalignment(inlineLabel, HPos.RIGHT);
GridPane.setConstraints(inlineLabel, 2, 3);
mEditorPane.getChildren().add(inlineLabel);
GridPane.setConstraints(getInlineToggleSwitch(), 3, 3);
mEditorPane.getChildren().add(getInlineToggleSwitch());
Label userNameLabel = new Label("User Name"); Label userNameLabel = new Label("User Name");
GridPane.setHalignment(userNameLabel, HPos.RIGHT); GridPane.setHalignment(userNameLabel, HPos.RIGHT);
GridPane.setConstraints(userNameLabel, 0, 4); GridPane.setConstraints(userNameLabel, 0, 4);
@@ -226,6 +240,19 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
return mMountPointTextField; return mMountPointTextField;
} }
private ToggleSwitch getInlineToggleSwitch()
{
if(mInlineToggleSwitch == null)
{
mInlineToggleSwitch = new ToggleSwitch();
mInlineToggleSwitch.setDisable(true);
mInlineToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
return mInlineToggleSwitch;
}
private TextField getUserNameTextField() private TextField getUserNameTextField()
{ {
if(mUserNameTextField == null) if(mUserNameTextField == null)

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2020 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.gui.playlist.streaming; package io.github.dsheirer.gui.playlist.streaming;

View File

@@ -1,18 +1,21 @@
/******************************************************************************* /*
* sdr-trunk * *****************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software: you can redistribute it and/or modify
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any * it under the terms of the GNU General Public License as published by
* later version. * 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 * This program is distributed in the hope that it will be useful,
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License
* If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.gui.preference; package io.github.dsheirer.gui.preference;

View File

@@ -1,7 +1,6 @@
/* /*
* ****************************************************************************** * *****************************************************************************
* sdrtrunk * Copyright (C) 2014-2022 Dennis Sheirer
* Copyright (C) 2014-2018 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -15,7 +14,7 @@
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* ***************************************************************************** * ****************************************************************************
*/ */
package io.github.dsheirer.gui.preference.directory; package io.github.dsheirer.gui.preference.directory;
@@ -63,6 +62,11 @@ public class DirectoryPreferenceEditor extends HBox
private Button mResetApplicationLogsButton; private Button mResetApplicationLogsButton;
private Label mApplicationLogsPathLabel; private Label mApplicationLogsPathLabel;
private Label mConfigurationLabel;
private Button mChangeConfigurationButton;
private Button mResetConfigurationButton;
private Label mConfigurationPathLabel;
private Label mEventLogsLabel; private Label mEventLogsLabel;
private Button mChangeEventLogsButton; private Button mChangeEventLogsButton;
private Button mResetEventLogsButton; private Button mResetEventLogsButton;
@@ -154,6 +158,19 @@ public class DirectoryPreferenceEditor extends HBox
mEditorPane.add(getResetApplicationLogsButton(), 3, row++); mEditorPane.add(getResetApplicationLogsButton(), 3, row++);
GridPane.setMargin(getConfigurationLabel(), new Insets(0, 10, 0, 0));
mEditorPane.add(getConfigurationLabel(), 0, row);
GridPane.setMargin(getConfigurationPathLabel(), new Insets(0, 10, 0, 0));
mEditorPane.add(getConfigurationPathLabel(), 1, row);
GridPane.setMargin(getChangeConfigurationButton(), new Insets(2, 10, 2, 0));
mEditorPane.add(getChangeConfigurationButton(), 2, row);
GridPane.setMargin(getResetConfigurationButton(), new Insets(2, 0, 2, 0));
mEditorPane.add(getResetConfigurationButton(), 3, row++);
GridPane.setMargin(getEventLogsLabel(), new Insets(0, 10, 0, 0)); GridPane.setMargin(getEventLogsLabel(), new Insets(0, 10, 0, 0));
mEditorPane.add(getEventLogsLabel(), 0, row); mEditorPane.add(getEventLogsLabel(), 0, row);
@@ -365,6 +382,71 @@ public class DirectoryPreferenceEditor extends HBox
return mApplicationLogsPathLabel; return mApplicationLogsPathLabel;
} }
private Label getConfigurationLabel()
{
if(mConfigurationLabel == null)
{
mConfigurationLabel = new Label("Configuration");
}
return mConfigurationLabel;
}
private Button getChangeConfigurationButton()
{
if(mChangeConfigurationButton == null)
{
mChangeConfigurationButton = new Button("Change...");
mChangeConfigurationButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setTitle("Select Configuration Folder");
directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryConfiguration().toFile());
Stage stage = (Stage)getChangeConfigurationButton().getScene().getWindow();
File selected = directoryChooser.showDialog(stage);
if(selected != null)
{
mDirectoryPreference.setDirectoryConfiguration(selected.toPath());
}
}
});
}
return mChangeConfigurationButton;
}
private Button getResetConfigurationButton()
{
if(mResetConfigurationButton == null)
{
mResetConfigurationButton = new Button("Reset");
mResetConfigurationButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
public void handle(ActionEvent event)
{
mDirectoryPreference.resetDirectoryConfiguration();
}
});
}
return mResetConfigurationButton;
}
private Label getConfigurationPathLabel()
{
if(mConfigurationPathLabel == null)
{
mConfigurationPathLabel = new Label(mDirectoryPreference.getDirectoryConfiguration().toString());
}
return mConfigurationPathLabel;
}
private Label getEventLogsLabel() private Label getEventLogsLabel()
{ {
if(mEventLogsLabel == null) if(mEventLogsLabel == null)

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.identifier; package io.github.dsheirer.identifier;

View File

@@ -1,18 +1,21 @@
/******************************************************************************* /*
* sdr-trunk * *****************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software: you can redistribute it and/or modify
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any * it under the terms of the GNU General Public License as published by
* later version. * 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 * This program is distributed in the hope that it will be useful,
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License
* If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.identifier; package io.github.dsheirer.identifier;
import io.github.dsheirer.protocol.Protocol; import io.github.dsheirer.protocol.Protocol;

View File

@@ -1,18 +1,21 @@
/******************************************************************************* /*
* sdr-trunk * *****************************************************************************
* Copyright (C) 2014-2018 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * This program is free software: you can redistribute it and/or modify
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any * it under the terms of the GNU General Public License as published by
* later version. * 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 * This program is distributed in the hope that it will be useful,
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * 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. * You should have received a copy of the GNU General Public License
* If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* * ****************************************************************************
******************************************************************************/ */
package io.github.dsheirer.identifier; package io.github.dsheirer.identifier;
/** /**

View File

@@ -278,29 +278,43 @@ public class IdentifierCollection
*/ */
public Identifier getFromIdentifier() public Identifier getFromIdentifier()
{ {
List<Identifier> fromIdentifiers = getIdentifiers(Role.FROM); Identifier from = getIdentifier(IdentifierClass.USER, Form.RADIO, Role.FROM);
if(!fromIdentifiers.isEmpty()) if(from == null)
{ {
return fromIdentifiers.get(0); List<Identifier> fromIdentifiers = getIdentifiers(Role.FROM);
if(!fromIdentifiers.isEmpty())
{
from = fromIdentifiers.get(0);
}
} }
return null; return from;
} }
/** /**
* Returns the first identifier in this collection that is assigned a FROM role * Returns the first identifier in this collection that is assigned a TO role
*/ */
public Identifier getToIdentifier() public Identifier getToIdentifier()
{ {
List<Identifier> toIdentifiers = getIdentifiers(Role.TO); Identifier to = getIdentifier(IdentifierClass.USER, Form.PATCH_GROUP, Role.TO);
if(!toIdentifiers.isEmpty()) if(to == null)
{ {
return toIdentifiers.get(0); to = getIdentifier(IdentifierClass.USER, Form.TALKGROUP, Role.TO);
} }
return null; if(to == null)
{
List<Identifier> toIdentifiers = getIdentifiers(Role.TO);
if(!toIdentifiers.isEmpty())
{
to = toIdentifiers.get(0);
}
}
return to;
} }
@Override @Override

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,20 +1,21 @@
/******************************************************************************* /*
* SDR Trunk * *****************************************************************************
* Copyright (C) 2014-2016 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/ * ****************************************************************************
*/
package io.github.dsheirer.module.decode; package io.github.dsheirer.module.decode;
import io.github.dsheirer.message.IMessage; import io.github.dsheirer.message.IMessage;

View File

@@ -1,6 +1,6 @@
/* /*
* ***************************************************************************** * *****************************************************************************
* Copyright (C) 2014-2021 Dennis Sheirer * Copyright (C) 2014-2022 Dennis Sheirer
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View File

@@ -1,23 +1,20 @@
/* /*
* *****************************************************************************
* Copyright (C) 2014-2022 Dennis Sheirer
* *
* * ****************************************************************************** * This program is free software: you can redistribute it and/or modify
* * Copyright (C) 2014-2019 Dennis Sheirer * it under the terms of the GNU General Public License as published by
* * * the Free Software Foundation, either version 3 of the License, or
* * This program is free software: you can redistribute it and/or modify * (at your option) any later version.
* * 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/ */
package io.github.dsheirer.module.decode; package io.github.dsheirer.module.decode;

Some files were not shown because too many files have changed in this diff Show More