mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
1772 Adds preference for patch group streaming to stream patch group calls as either a)patch group, or b)each individual talkgroup or radio that forms the patch group.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* Copyright (C) 2014-2023 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
|
||||
@@ -28,12 +28,9 @@ import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
|
||||
import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
||||
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.duplicate.DuplicateCallDetectionPreference;
|
||||
import io.github.dsheirer.preference.duplicate.CallManagementPreference;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -42,6 +39,8 @@ import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Detects duplicate calls that occur within the same system. This detector is thread safe for the receive() method.
|
||||
@@ -52,18 +51,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
public class DuplicateCallDetector implements Listener<AudioSegment>
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(DuplicateCallDetector.class);
|
||||
private DuplicateCallDetectionPreference mDuplicateCallDetectionPreference;
|
||||
private CallManagementPreference mCallManagementPreference;
|
||||
private Map<String,SystemDuplicateCallDetector> mDetectorMap = new HashMap();
|
||||
|
||||
public DuplicateCallDetector(UserPreferences userPreferences)
|
||||
{
|
||||
mDuplicateCallDetectionPreference = userPreferences.getDuplicateCallDetectionPreference();
|
||||
mCallManagementPreference = userPreferences.getDuplicateCallDetectionPreference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(AudioSegment audioSegment)
|
||||
{
|
||||
if(mDuplicateCallDetectionPreference.isDuplicateCallDetectionEnabled())
|
||||
if(mCallManagementPreference.isDuplicateCallDetectionEnabled())
|
||||
{
|
||||
Identifier identifier = audioSegment.getIdentifierCollection()
|
||||
.getIdentifier(IdentifierClass.CONFIGURATION, Form.SYSTEM, Role.ANY);
|
||||
@@ -137,7 +136,7 @@ public class DuplicateCallDetector implements Listener<AudioSegment>
|
||||
*/
|
||||
private boolean isDuplicate(AudioSegment segment1, AudioSegment segment2)
|
||||
{
|
||||
if(mDuplicateCallDetectionPreference.isDuplicateCallDetectionByTalkgroupEnabled())
|
||||
if(mCallManagementPreference.isDuplicateCallDetectionByTalkgroupEnabled())
|
||||
{
|
||||
//Step 1 check for duplicate TO values
|
||||
List<Identifier> to1 = segment1.getIdentifierCollection().getIdentifiers(Role.TO);
|
||||
@@ -149,7 +148,7 @@ public class DuplicateCallDetector implements Listener<AudioSegment>
|
||||
}
|
||||
}
|
||||
|
||||
if(mDuplicateCallDetectionPreference.isDuplicateCallDetectionByRadioEnabled())
|
||||
if(mCallManagementPreference.isDuplicateCallDetectionByRadioEnabled())
|
||||
{
|
||||
//Step 2 check for duplicate FROM values
|
||||
List<Identifier> from1 = segment1.getIdentifierCollection().getIdentifiers(Role.FROM);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2023 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
|
||||
@@ -19,25 +19,34 @@
|
||||
|
||||
package io.github.dsheirer.audio.broadcast;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||
import io.github.dsheirer.audio.AudioSegment;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.identifier.MutableIdentifierCollection;
|
||||
import io.github.dsheirer.identifier.Role;
|
||||
import io.github.dsheirer.identifier.patch.PatchGroup;
|
||||
import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.AudioSegmentRecorder;
|
||||
import io.github.dsheirer.record.RecordFormat;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import io.github.dsheirer.util.TimeStamp;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Audio streaming manager monitors audio segments through completion and creates temporary streaming recordings on
|
||||
@@ -138,29 +147,60 @@ public class AudioStreamingManager implements Listener<AudioSegment>
|
||||
|
||||
if(mAudioRecordingListener != null && audioSegment.hasBroadcastChannels())
|
||||
{
|
||||
Path path = getTemporaryRecordingPath();
|
||||
long length = 0;
|
||||
|
||||
for(float[] audioBuffer: audioSegment.getAudioBuffers())
|
||||
{
|
||||
length += audioBuffer.length;
|
||||
}
|
||||
|
||||
length /= 8; //Sample rate is 8000 samples per second, or 8 samples per millisecond.
|
||||
|
||||
try
|
||||
{
|
||||
AudioSegmentRecorder.record(audioSegment, path, RecordFormat.MP3, mUserPreferences);
|
||||
IdentifierCollection identifierCollectionCopy =
|
||||
IdentifierCollection identifiers =
|
||||
new IdentifierCollection(audioSegment.getIdentifierCollection().getIdentifiers());
|
||||
|
||||
AudioRecording audioRecording = new AudioRecording(path, audioSegment.getBroadcastChannels(),
|
||||
identifierCollectionCopy, audioSegment.getStartTimestamp(), length);
|
||||
mAudioRecordingListener.receive(audioRecording);
|
||||
}
|
||||
catch(IOException ioe)
|
||||
if(identifiers.getToIdentifier() instanceof PatchGroupIdentifier patchGroupIdentifier)
|
||||
{
|
||||
mLog.error("Error recording temporary stream MP3");
|
||||
if(mUserPreferences.getDuplicateCallDetectionPreference()
|
||||
.getPatchGroupStreamingOption() == PatchGroupStreamingOption.TALKGROUPS)
|
||||
{
|
||||
//Decompose the patch group into the individual (patched) talkgroups and process the audio
|
||||
//segment for each patched talkgroup.
|
||||
PatchGroup patchGroup = patchGroupIdentifier.getValue();
|
||||
|
||||
List<Identifier> ids = new ArrayList<>();
|
||||
ids.addAll(patchGroup.getPatchedTalkgroupIdentifiers());
|
||||
ids.addAll(patchGroup.getPatchedRadioIdentifiers());
|
||||
|
||||
//If there are no patched radios/talkgroups, override user preference and stream as a patch group
|
||||
if(ids.isEmpty() || audioSegment.getAliasList() == null)
|
||||
{
|
||||
processAudioSegment(audioSegment, identifiers, audioSegment.getBroadcastChannels());
|
||||
}
|
||||
else
|
||||
{
|
||||
AliasList aliasList = audioSegment.getAliasList();
|
||||
|
||||
for(Identifier identifier: ids)
|
||||
{
|
||||
List<Alias> aliases = aliasList.getAliases(identifier);
|
||||
Set<BroadcastChannel> broadcastChannels = new HashSet<>();
|
||||
for(Alias alias: aliases)
|
||||
{
|
||||
broadcastChannels.addAll(alias.getBroadcastChannels());
|
||||
}
|
||||
|
||||
if(!broadcastChannels.isEmpty())
|
||||
{
|
||||
MutableIdentifierCollection decomposedIdentifiers =
|
||||
new MutableIdentifierCollection(identifiers.getIdentifiers());
|
||||
//Remove patch group TO identifier & replace with the patched talkgroup/radio
|
||||
decomposedIdentifiers.remove(Role.TO);
|
||||
decomposedIdentifiers.update(identifier);
|
||||
processAudioSegment(audioSegment, decomposedIdentifiers, broadcastChannels);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processAudioSegment(audioSegment, identifiers, audioSegment.getBroadcastChannels());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
processAudioSegment(audioSegment, identifiers, audioSegment.getBroadcastChannels());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +209,40 @@ public class AudioStreamingManager implements Listener<AudioSegment>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an audio segment for streaming by creating a temporary MP3 recording and submitting the recording
|
||||
* to the specific broadcast channel(s).
|
||||
* @param audioSegment to process for streaming
|
||||
* @param identifierCollection to use for the streamed audio recording.
|
||||
* @param broadcastChannels to receive the audio recording
|
||||
*/
|
||||
private void processAudioSegment(AudioSegment audioSegment, IdentifierCollection identifierCollection,
|
||||
Set<BroadcastChannel> broadcastChannels)
|
||||
{
|
||||
Path path = getTemporaryRecordingPath();
|
||||
long length = 0;
|
||||
|
||||
for(float[] audioBuffer: audioSegment.getAudioBuffers())
|
||||
{
|
||||
length += audioBuffer.length;
|
||||
}
|
||||
|
||||
length /= 8; //Sample rate is 8000 samples per second, or 8 samples per millisecond.
|
||||
|
||||
try
|
||||
{
|
||||
AudioSegmentRecorder.record(audioSegment, path, RecordFormat.MP3, mUserPreferences, identifierCollection);
|
||||
|
||||
AudioRecording audioRecording = new AudioRecording(path, broadcastChannels, identifierCollection,
|
||||
audioSegment.getStartTimestamp(), length);
|
||||
mAudioRecordingListener.receive(audioRecording);
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
mLog.error("Error recording temporary stream MP3");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary streaming recording file path
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 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;
|
||||
|
||||
/**
|
||||
* Options for streaming management of patch groups. These options are used when streaming an audio call that is
|
||||
* tagged to a patch group. The audio will either be streamed once and identified as the patch group, or it will
|
||||
* be streamed multiple times, once for each individual patched talkgroup.
|
||||
*/
|
||||
public enum PatchGroupStreamingOption
|
||||
{
|
||||
PATCH_GROUP("Patch Group"),
|
||||
TALKGROUPS("Individual Talkgroups");
|
||||
|
||||
private String mLabel;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param label to display
|
||||
*/
|
||||
PatchGroupStreamingOption(String label)
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ public class MBECallSequenceConverter
|
||||
|
||||
try
|
||||
{
|
||||
AudioSegmentRecorder.recordWAVE(audioSegment, outputPath);
|
||||
AudioSegmentRecorder.recordWAVE(audioSegment, outputPath, audioSegment.getIdentifierCollection());
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
|
||||
@@ -21,9 +21,9 @@ package io.github.dsheirer.gui.preference;
|
||||
|
||||
import io.github.dsheirer.gui.preference.application.ApplicationPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.calibration.VectorCalibrationPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.call.CallManagementPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.decoder.JmbeLibraryPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.directory.DirectoryPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.duplicate.DuplicateCallPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.mp3.MP3PreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.playback.PlaybackPreferenceEditor;
|
||||
import io.github.dsheirer.gui.preference.record.RecordPreferenceEditor;
|
||||
@@ -42,8 +42,8 @@ public class PreferenceEditorFactory
|
||||
{
|
||||
case APPLICATION:
|
||||
return new ApplicationPreferenceEditor(userPreferences);
|
||||
case AUDIO_DUPLICATE_CALL_DETECTION:
|
||||
return new DuplicateCallPreferenceEditor(userPreferences);
|
||||
case AUDIO_CALL_MANAGEMENT:
|
||||
return new CallManagementPreferenceEditor(userPreferences);
|
||||
case AUDIO_MP3:
|
||||
return new MP3PreferenceEditor(userPreferences);
|
||||
case AUDIO_OUTPUT:
|
||||
|
||||
@@ -31,7 +31,7 @@ public enum PreferenceEditorType
|
||||
AUDIO_MP3("MP3"),
|
||||
AUDIO_RECORD("Record"),
|
||||
AUDIO_OUTPUT("Output/Tones"),
|
||||
AUDIO_DUPLICATE_CALL_DETECTION("Duplicate Calls"),
|
||||
AUDIO_CALL_MANAGEMENT("Call Management"),
|
||||
SOURCE_TUNERS("Tuners"),
|
||||
TALKGROUP_FORMAT("Talkgroup & Radio ID"),
|
||||
VECTOR_CALIBRATION("Vector Calibration"),
|
||||
|
||||
@@ -171,7 +171,7 @@ public class UserPreferencesEditor extends BorderPane
|
||||
applicationItem.setExpanded(true);
|
||||
|
||||
TreeItem<String> audioItem = new TreeItem<>("Audio");
|
||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_DUPLICATE_CALL_DETECTION));
|
||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_CALL_MANAGEMENT));
|
||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_MP3));
|
||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_OUTPUT));
|
||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_RECORD));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* Copyright (C) 2014-2023 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
|
||||
@@ -17,12 +17,16 @@
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.gui.preference.duplicate;
|
||||
package io.github.dsheirer.gui.preference.call;
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.PatchGroupStreamingOption;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.duplicate.DuplicateCallDetectionPreference;
|
||||
import io.github.dsheirer.preference.duplicate.CallManagementPreference;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.layout.GridPane;
|
||||
@@ -33,23 +37,24 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Preference settings for duplicate call audio handling
|
||||
* Preference settings for audio call management for duplicate calls and patch group streaming.
|
||||
*/
|
||||
public class DuplicateCallPreferenceEditor extends HBox
|
||||
public class CallManagementPreferenceEditor extends HBox
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(DuplicateCallPreferenceEditor.class);
|
||||
private DuplicateCallDetectionPreference mPreference;
|
||||
private final static Logger mLog = LoggerFactory.getLogger(CallManagementPreferenceEditor.class);
|
||||
private CallManagementPreference mPreference;
|
||||
private GridPane mEditorPane;
|
||||
private ToggleSwitch mDetectDuplicateTalkgroups;
|
||||
private ToggleSwitch mDetectDuplicateRadios;
|
||||
private ToggleSwitch mSuppressDuplicateListening;
|
||||
private ToggleSwitch mSuppressDuplicateRecording;
|
||||
private ToggleSwitch mSuppressDuplicateStreaming;
|
||||
private ComboBox<PatchGroupStreamingOption> mPatchGroupStreamingOptionComboBox;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
*/
|
||||
public DuplicateCallPreferenceEditor(UserPreferences userPreferences)
|
||||
public CallManagementPreferenceEditor(UserPreferences userPreferences)
|
||||
{
|
||||
mPreference = userPreferences.getDuplicateCallDetectionPreference();
|
||||
|
||||
@@ -134,6 +139,19 @@ public class DuplicateCallPreferenceEditor extends HBox
|
||||
streamingLabel.setWrapText(true);
|
||||
GridPane.setConstraints(streamingLabel, 1, row);
|
||||
mEditorPane.getChildren().add(streamingLabel);
|
||||
|
||||
Separator separator2 = new Separator();
|
||||
GridPane.setHgrow(separator2, Priority.ALWAYS);
|
||||
GridPane.setConstraints(separator2, 0, ++row, 2, 1);
|
||||
mEditorPane.getChildren().add(separator2);
|
||||
|
||||
Label patchGroupLabel = new Label("Patch Group Streaming. Stream a patch group call as:");
|
||||
patchGroupLabel.setWrapText(true);
|
||||
GridPane.setConstraints(patchGroupLabel, 0, ++row, 2, 1);
|
||||
mEditorPane.getChildren().add(patchGroupLabel);
|
||||
|
||||
GridPane.setConstraints(getPatchGroupStreamingOptionComboBox(), 0, ++row, 2, 1);
|
||||
mEditorPane.getChildren().add(getPatchGroupStreamingOptionComboBox());
|
||||
}
|
||||
|
||||
return mEditorPane;
|
||||
@@ -212,4 +230,23 @@ public class DuplicateCallPreferenceEditor extends HBox
|
||||
|
||||
return mSuppressDuplicateStreaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combo box for presenting the patch group streaming options.
|
||||
* @return combo box.
|
||||
*/
|
||||
private ComboBox<PatchGroupStreamingOption> getPatchGroupStreamingOptionComboBox()
|
||||
{
|
||||
if(mPatchGroupStreamingOptionComboBox == null)
|
||||
{
|
||||
ObservableList<PatchGroupStreamingOption> options = FXCollections.observableArrayList();
|
||||
options.addAll(PatchGroupStreamingOption.values());
|
||||
mPatchGroupStreamingOptionComboBox = new ComboBox<>(options);
|
||||
mPatchGroupStreamingOptionComboBox.getSelectionModel().select(mPreference.getPatchGroupStreamingOption());
|
||||
mPatchGroupStreamingOptionComboBox.getSelectionModel().selectedItemProperty()
|
||||
.addListener((observable, oldValue, newValue) -> mPreference.setPatchGroupStreamingOption(newValue));
|
||||
}
|
||||
|
||||
return mPatchGroupStreamingOptionComboBox;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import io.github.dsheirer.preference.application.ApplicationPreference;
|
||||
import io.github.dsheirer.preference.calibration.VectorCalibrationPreference;
|
||||
import io.github.dsheirer.preference.decoder.JmbeLibraryPreference;
|
||||
import io.github.dsheirer.preference.directory.DirectoryPreference;
|
||||
import io.github.dsheirer.preference.duplicate.DuplicateCallDetectionPreference;
|
||||
import io.github.dsheirer.preference.duplicate.CallManagementPreference;
|
||||
import io.github.dsheirer.preference.event.DecodeEventPreference;
|
||||
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
|
||||
import io.github.dsheirer.preference.javafx.JavaFxPreferences;
|
||||
@@ -60,7 +60,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
||||
private ChannelMultiFrequencyPreference mChannelMultiFrequencyPreference;
|
||||
private DecodeEventPreference mDecodeEventPreference;
|
||||
private DirectoryPreference mDirectoryPreference;
|
||||
private DuplicateCallDetectionPreference mDuplicateCallDetectionPreference;
|
||||
private CallManagementPreference mDuplicateCallDetectionPreference;
|
||||
private JmbeLibraryPreference mJmbeLibraryPreference;
|
||||
private MP3Preference mMP3Preference;
|
||||
private PlaybackPreference mPlaybackPreference;
|
||||
@@ -208,7 +208,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
||||
/**
|
||||
* Duplicate call detection preferences
|
||||
*/
|
||||
public DuplicateCallDetectionPreference getDuplicateCallDetectionPreference()
|
||||
public CallManagementPreference getDuplicateCallDetectionPreference()
|
||||
{
|
||||
return mDuplicateCallDetectionPreference;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
||||
mChannelMultiFrequencyPreference = new ChannelMultiFrequencyPreference(this::receive);
|
||||
mDecodeEventPreference = new DecodeEventPreference(this::receive);
|
||||
mDirectoryPreference = new DirectoryPreference(this::receive);
|
||||
mDuplicateCallDetectionPreference = new DuplicateCallDetectionPreference(this::receive);
|
||||
mDuplicateCallDetectionPreference = new CallManagementPreference(this::receive);
|
||||
mJmbeLibraryPreference = new JmbeLibraryPreference(this::receive);
|
||||
mMP3Preference = new MP3Preference(this::receive);
|
||||
mPlaybackPreference = new PlaybackPreference(this::receive);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
* Copyright (C) 2014-2023 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
|
||||
@@ -19,38 +19,40 @@
|
||||
|
||||
package io.github.dsheirer.preference.duplicate;
|
||||
|
||||
import io.github.dsheirer.audio.broadcast.PatchGroupStreamingOption;
|
||||
import io.github.dsheirer.preference.Preference;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import java.util.prefs.Preferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
/**
|
||||
* User preferences for duplicate call detection
|
||||
* User preferences for call management
|
||||
*/
|
||||
public class DuplicateCallDetectionPreference extends Preference
|
||||
public class CallManagementPreference extends Preference
|
||||
{
|
||||
private static final String PREFERENCE_KEY_DETECT_DUPLICATE_TALKGROUP = "duplicate.call.detect.talkgroup";
|
||||
private static final String PREFERENCE_KEY_DETECT_DUPLICATE_RADIO = "duplicate.call.detect.radio";
|
||||
private static final String PREFERENCE_KEY_SUPPRESS_DUPLICATE_PLAYBACK = "suppress.duplicate.audio.playback";
|
||||
private static final String PREFERENCE_KEY_SUPPRESS_DUPLICATE_RECORDING = "suppress.duplicate.audio.recording";
|
||||
private static final String PREFERENCE_KEY_SUPPRESS_DUPLICATE_STREAMING = "suppress.duplicate.audio.streaming";
|
||||
private static final String PREFERENCE_KEY_PATCHGROUP_STREAMING = "patchgroup.streaming";
|
||||
|
||||
private final static Logger mLog = LoggerFactory.getLogger(DuplicateCallDetectionPreference.class);
|
||||
private Preferences mPreferences = Preferences.userNodeForPackage(DuplicateCallDetectionPreference.class);
|
||||
private final static Logger mLog = LoggerFactory.getLogger(CallManagementPreference.class);
|
||||
private Preferences mPreferences = Preferences.userNodeForPackage(CallManagementPreference.class);
|
||||
private Boolean mDuplicateCallDetectionByTalkgroupEnabled;
|
||||
private Boolean mDuplicateCallDetectionByRadioEnabled;
|
||||
private Boolean mDuplicatePlaybackSuppressionEnabled;
|
||||
private Boolean mDuplicateRecordingSuppressionEnabled;
|
||||
private Boolean mDuplicateStreamingSuppressionEnabled;
|
||||
private PatchGroupStreamingOption mPatchGroupStreamingOption;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param updateListener to receive notifications that a preference has been updated
|
||||
*/
|
||||
public DuplicateCallDetectionPreference(Listener<PreferenceType> updateListener)
|
||||
public CallManagementPreference(Listener<PreferenceType> updateListener)
|
||||
{
|
||||
super(updateListener);
|
||||
}
|
||||
@@ -182,6 +184,51 @@ public class DuplicateCallDetectionPreference extends Preference
|
||||
{
|
||||
mPreferences.putBoolean(PREFERENCE_KEY_SUPPRESS_DUPLICATE_STREAMING, enabled);
|
||||
mDuplicateStreamingSuppressionEnabled = enabled;
|
||||
notifyPreferenceUpdated();;
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch group streaming option preference.
|
||||
* @return option.
|
||||
*/
|
||||
public PatchGroupStreamingOption getPatchGroupStreamingOption()
|
||||
{
|
||||
if(mPatchGroupStreamingOption == null)
|
||||
{
|
||||
String option = mPreferences.get(PREFERENCE_KEY_PATCHGROUP_STREAMING, PatchGroupStreamingOption.PATCH_GROUP.name());
|
||||
|
||||
if(option != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
mPatchGroupStreamingOption = PatchGroupStreamingOption.valueOf(option);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Ignore ... we'll use the default value.
|
||||
}
|
||||
}
|
||||
|
||||
if(mPatchGroupStreamingOption == null)
|
||||
{
|
||||
mPatchGroupStreamingOption = PatchGroupStreamingOption.PATCH_GROUP;
|
||||
}
|
||||
}
|
||||
|
||||
return mPatchGroupStreamingOption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the patch group streaming option preference.
|
||||
* @param patchGroupStreamingOption preference
|
||||
*/
|
||||
public void setPatchGroupStreamingOption(PatchGroupStreamingOption patchGroupStreamingOption)
|
||||
{
|
||||
if(patchGroupStreamingOption != null)
|
||||
{
|
||||
mPreferences.put(PREFERENCE_KEY_PATCHGROUP_STREAMING, patchGroupStreamingOption.name());
|
||||
mPatchGroupStreamingOption = patchGroupStreamingOption;
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2022 Dennis Sheirer
|
||||
* Copyright (C) 2014-2023 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
|
||||
@@ -24,6 +24,7 @@ import io.github.dsheirer.audio.AudioSegment;
|
||||
import io.github.dsheirer.audio.convert.InputAudioFormat;
|
||||
import io.github.dsheirer.audio.convert.MP3AudioConverter;
|
||||
import io.github.dsheirer.audio.convert.MP3Setting;
|
||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.wave.AudioMetadata;
|
||||
import io.github.dsheirer.record.wave.AudioMetadataUtils;
|
||||
@@ -58,14 +59,28 @@ public class AudioSegmentRecorder
|
||||
*/
|
||||
public static void record(AudioSegment audioSegment, Path path, RecordFormat recordFormat,
|
||||
UserPreferences userPreferences) throws IOException
|
||||
{
|
||||
record(audioSegment, path, recordFormat, userPreferences, audioSegment.getIdentifierCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the audio segment to the specified path using the specified recording format
|
||||
* @param audioSegment to record
|
||||
* @param path for the recording
|
||||
* @param recordFormat to use (WAVE, MP3)
|
||||
* @param identifierCollection to use instead of the audioSegment's embedded collection.
|
||||
* @throws IOException on any errors
|
||||
*/
|
||||
public static void record(AudioSegment audioSegment, Path path, RecordFormat recordFormat,
|
||||
UserPreferences userPreferences, IdentifierCollection identifierCollection) throws IOException
|
||||
{
|
||||
switch(recordFormat)
|
||||
{
|
||||
case MP3:
|
||||
recordMP3(audioSegment, path, userPreferences);
|
||||
recordMP3(audioSegment, path, userPreferences, identifierCollection);
|
||||
break;
|
||||
case WAVE:
|
||||
recordWAVE(audioSegment, path);
|
||||
recordWAVE(audioSegment, path, identifierCollection);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unrecognized recording format [" + recordFormat.name() + "]");
|
||||
@@ -76,16 +91,19 @@ public class AudioSegmentRecorder
|
||||
* Records the audio segment as an MP3 file to the specified path.
|
||||
* @param audioSegment to record
|
||||
* @param path for the recording
|
||||
* @param userPreferences for configuration
|
||||
* @param identifierCollection to use instead of the collection embedded in the audio segment
|
||||
* @throws IOException on any errors
|
||||
*/
|
||||
public static void recordMP3(AudioSegment audioSegment, Path path, UserPreferences userPreferences) throws IOException
|
||||
public static void recordMP3(AudioSegment audioSegment, Path path, UserPreferences userPreferences,
|
||||
IdentifierCollection identifierCollection) throws IOException
|
||||
{
|
||||
if(audioSegment.hasAudio())
|
||||
{
|
||||
OutputStream outputStream = new FileOutputStream(path.toFile());
|
||||
|
||||
//Write ID3 metadata
|
||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(audioSegment.getIdentifierCollection(),
|
||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(identifierCollection,
|
||||
audioSegment.getAliasList());
|
||||
|
||||
byte[] id3Bytes = AudioMetadataUtils.getMP3ID3(metadataMap);
|
||||
@@ -123,9 +141,10 @@ public class AudioSegmentRecorder
|
||||
* Records the audio segment as a WAVe file to the specified path.
|
||||
* @param audioSegment to record
|
||||
* @param path for the recording
|
||||
* @param identifierCollection to use instead of the audioSegment's embedded identifier collection
|
||||
* @throws IOException on any errors
|
||||
*/
|
||||
public static void recordWAVE(AudioSegment audioSegment, Path path) throws IOException
|
||||
public static void recordWAVE(AudioSegment audioSegment, Path path, IdentifierCollection identifierCollection) throws IOException
|
||||
{
|
||||
if(audioSegment.hasAudio())
|
||||
{
|
||||
@@ -136,7 +155,7 @@ public class AudioSegmentRecorder
|
||||
writer.writeData(ConversionUtils.convertToSigned16BitSamples(audioBuffer));
|
||||
}
|
||||
|
||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(audioSegment.getIdentifierCollection(),
|
||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(identifierCollection,
|
||||
audioSegment.getAliasList());
|
||||
|
||||
ByteBuffer listChunk = AudioMetadataUtils.getLISTChunk(metadataMap);
|
||||
|
||||
Reference in New Issue
Block a user