mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-15 01:57:39 -05:00
Merge pull request #1773 from DSheirer/1772-patch-group-streaming
1772 Patch Group Streaming Preference (Patch Group vs Individual Talkgroups)
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
|
* 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
|
||||||
@@ -28,12 +28,9 @@ import io.github.dsheirer.identifier.patch.PatchGroupIdentifier;
|
|||||||
import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
||||||
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
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.sample.Listener;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -42,6 +39,8 @@ import java.util.concurrent.LinkedTransferQueue;
|
|||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
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.
|
* 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>
|
public class DuplicateCallDetector implements Listener<AudioSegment>
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(DuplicateCallDetector.class);
|
private final static Logger mLog = LoggerFactory.getLogger(DuplicateCallDetector.class);
|
||||||
private DuplicateCallDetectionPreference mDuplicateCallDetectionPreference;
|
private CallManagementPreference mCallManagementPreference;
|
||||||
private Map<String,SystemDuplicateCallDetector> mDetectorMap = new HashMap();
|
private Map<String,SystemDuplicateCallDetector> mDetectorMap = new HashMap();
|
||||||
|
|
||||||
public DuplicateCallDetector(UserPreferences userPreferences)
|
public DuplicateCallDetector(UserPreferences userPreferences)
|
||||||
{
|
{
|
||||||
mDuplicateCallDetectionPreference = userPreferences.getDuplicateCallDetectionPreference();
|
mCallManagementPreference = userPreferences.getDuplicateCallDetectionPreference();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void receive(AudioSegment audioSegment)
|
public void receive(AudioSegment audioSegment)
|
||||||
{
|
{
|
||||||
if(mDuplicateCallDetectionPreference.isDuplicateCallDetectionEnabled())
|
if(mCallManagementPreference.isDuplicateCallDetectionEnabled())
|
||||||
{
|
{
|
||||||
Identifier identifier = audioSegment.getIdentifierCollection()
|
Identifier identifier = audioSegment.getIdentifierCollection()
|
||||||
.getIdentifier(IdentifierClass.CONFIGURATION, Form.SYSTEM, Role.ANY);
|
.getIdentifier(IdentifierClass.CONFIGURATION, Form.SYSTEM, Role.ANY);
|
||||||
@@ -137,7 +136,7 @@ public class DuplicateCallDetector implements Listener<AudioSegment>
|
|||||||
*/
|
*/
|
||||||
private boolean isDuplicate(AudioSegment segment1, AudioSegment segment2)
|
private boolean isDuplicate(AudioSegment segment1, AudioSegment segment2)
|
||||||
{
|
{
|
||||||
if(mDuplicateCallDetectionPreference.isDuplicateCallDetectionByTalkgroupEnabled())
|
if(mCallManagementPreference.isDuplicateCallDetectionByTalkgroupEnabled())
|
||||||
{
|
{
|
||||||
//Step 1 check for duplicate TO values
|
//Step 1 check for duplicate TO values
|
||||||
List<Identifier> to1 = segment1.getIdentifierCollection().getIdentifiers(Role.TO);
|
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
|
//Step 2 check for duplicate FROM values
|
||||||
List<Identifier> from1 = segment1.getIdentifierCollection().getIdentifiers(Role.FROM);
|
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
|
* 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
|
||||||
@@ -19,25 +19,34 @@
|
|||||||
|
|
||||||
package io.github.dsheirer.audio.broadcast;
|
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.audio.AudioSegment;
|
||||||
|
import io.github.dsheirer.identifier.Identifier;
|
||||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
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.preference.UserPreferences;
|
||||||
import io.github.dsheirer.record.AudioSegmentRecorder;
|
import io.github.dsheirer.record.AudioSegmentRecorder;
|
||||||
import io.github.dsheirer.record.RecordFormat;
|
import io.github.dsheirer.record.RecordFormat;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
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 org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.LinkedTransferQueue;
|
import java.util.concurrent.LinkedTransferQueue;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
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
|
* 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())
|
if(mAudioRecordingListener != null && audioSegment.hasBroadcastChannels())
|
||||||
{
|
{
|
||||||
Path path = getTemporaryRecordingPath();
|
IdentifierCollection identifiers =
|
||||||
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 =
|
|
||||||
new IdentifierCollection(audioSegment.getIdentifierCollection().getIdentifiers());
|
new IdentifierCollection(audioSegment.getIdentifierCollection().getIdentifiers());
|
||||||
|
|
||||||
AudioRecording audioRecording = new AudioRecording(path, audioSegment.getBroadcastChannels(),
|
if(identifiers.getToIdentifier() instanceof PatchGroupIdentifier patchGroupIdentifier)
|
||||||
identifierCollectionCopy, audioSegment.getStartTimestamp(), length);
|
|
||||||
mAudioRecordingListener.receive(audioRecording);
|
|
||||||
}
|
|
||||||
catch(IOException ioe)
|
|
||||||
{
|
{
|
||||||
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
|
* 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
|
try
|
||||||
{
|
{
|
||||||
AudioSegmentRecorder.recordWAVE(audioSegment, outputPath);
|
AudioSegmentRecorder.recordWAVE(audioSegment, outputPath, audioSegment.getIdentifierCollection());
|
||||||
}
|
}
|
||||||
catch(IOException ioe)
|
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.application.ApplicationPreferenceEditor;
|
||||||
import io.github.dsheirer.gui.preference.calibration.VectorCalibrationPreferenceEditor;
|
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.decoder.JmbeLibraryPreferenceEditor;
|
||||||
import io.github.dsheirer.gui.preference.directory.DirectoryPreferenceEditor;
|
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.mp3.MP3PreferenceEditor;
|
||||||
import io.github.dsheirer.gui.preference.playback.PlaybackPreferenceEditor;
|
import io.github.dsheirer.gui.preference.playback.PlaybackPreferenceEditor;
|
||||||
import io.github.dsheirer.gui.preference.record.RecordPreferenceEditor;
|
import io.github.dsheirer.gui.preference.record.RecordPreferenceEditor;
|
||||||
@@ -42,8 +42,8 @@ public class PreferenceEditorFactory
|
|||||||
{
|
{
|
||||||
case APPLICATION:
|
case APPLICATION:
|
||||||
return new ApplicationPreferenceEditor(userPreferences);
|
return new ApplicationPreferenceEditor(userPreferences);
|
||||||
case AUDIO_DUPLICATE_CALL_DETECTION:
|
case AUDIO_CALL_MANAGEMENT:
|
||||||
return new DuplicateCallPreferenceEditor(userPreferences);
|
return new CallManagementPreferenceEditor(userPreferences);
|
||||||
case AUDIO_MP3:
|
case AUDIO_MP3:
|
||||||
return new MP3PreferenceEditor(userPreferences);
|
return new MP3PreferenceEditor(userPreferences);
|
||||||
case AUDIO_OUTPUT:
|
case AUDIO_OUTPUT:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public enum PreferenceEditorType
|
|||||||
AUDIO_MP3("MP3"),
|
AUDIO_MP3("MP3"),
|
||||||
AUDIO_RECORD("Record"),
|
AUDIO_RECORD("Record"),
|
||||||
AUDIO_OUTPUT("Output/Tones"),
|
AUDIO_OUTPUT("Output/Tones"),
|
||||||
AUDIO_DUPLICATE_CALL_DETECTION("Duplicate Calls"),
|
AUDIO_CALL_MANAGEMENT("Call Management"),
|
||||||
SOURCE_TUNERS("Tuners"),
|
SOURCE_TUNERS("Tuners"),
|
||||||
TALKGROUP_FORMAT("Talkgroup & Radio ID"),
|
TALKGROUP_FORMAT("Talkgroup & Radio ID"),
|
||||||
VECTOR_CALIBRATION("Vector Calibration"),
|
VECTOR_CALIBRATION("Vector Calibration"),
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public class UserPreferencesEditor extends BorderPane
|
|||||||
applicationItem.setExpanded(true);
|
applicationItem.setExpanded(true);
|
||||||
|
|
||||||
TreeItem<String> audioItem = new TreeItem<>("Audio");
|
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_MP3));
|
||||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_OUTPUT));
|
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_OUTPUT));
|
||||||
audioItem.getChildren().add(new TreeItem(PreferenceEditorType.AUDIO_RECORD));
|
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
|
* 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
|
||||||
@@ -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.UserPreferences;
|
||||||
import io.github.dsheirer.preference.duplicate.DuplicateCallDetectionPreference;
|
import io.github.dsheirer.preference.duplicate.CallManagementPreference;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.Separator;
|
import javafx.scene.control.Separator;
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
@@ -33,23 +37,24 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
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 final static Logger mLog = LoggerFactory.getLogger(CallManagementPreferenceEditor.class);
|
||||||
private DuplicateCallDetectionPreference mPreference;
|
private CallManagementPreference mPreference;
|
||||||
private GridPane mEditorPane;
|
private GridPane mEditorPane;
|
||||||
private ToggleSwitch mDetectDuplicateTalkgroups;
|
private ToggleSwitch mDetectDuplicateTalkgroups;
|
||||||
private ToggleSwitch mDetectDuplicateRadios;
|
private ToggleSwitch mDetectDuplicateRadios;
|
||||||
private ToggleSwitch mSuppressDuplicateListening;
|
private ToggleSwitch mSuppressDuplicateListening;
|
||||||
private ToggleSwitch mSuppressDuplicateRecording;
|
private ToggleSwitch mSuppressDuplicateRecording;
|
||||||
private ToggleSwitch mSuppressDuplicateStreaming;
|
private ToggleSwitch mSuppressDuplicateStreaming;
|
||||||
|
private ComboBox<PatchGroupStreamingOption> mPatchGroupStreamingOptionComboBox;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an instance
|
* Constructs an instance
|
||||||
*/
|
*/
|
||||||
public DuplicateCallPreferenceEditor(UserPreferences userPreferences)
|
public CallManagementPreferenceEditor(UserPreferences userPreferences)
|
||||||
{
|
{
|
||||||
mPreference = userPreferences.getDuplicateCallDetectionPreference();
|
mPreference = userPreferences.getDuplicateCallDetectionPreference();
|
||||||
|
|
||||||
@@ -134,6 +139,19 @@ public class DuplicateCallPreferenceEditor extends HBox
|
|||||||
streamingLabel.setWrapText(true);
|
streamingLabel.setWrapText(true);
|
||||||
GridPane.setConstraints(streamingLabel, 1, row);
|
GridPane.setConstraints(streamingLabel, 1, row);
|
||||||
mEditorPane.getChildren().add(streamingLabel);
|
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;
|
return mEditorPane;
|
||||||
@@ -212,4 +230,23 @@ public class DuplicateCallPreferenceEditor extends HBox
|
|||||||
|
|
||||||
return mSuppressDuplicateStreaming;
|
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.calibration.VectorCalibrationPreference;
|
||||||
import io.github.dsheirer.preference.decoder.JmbeLibraryPreference;
|
import io.github.dsheirer.preference.decoder.JmbeLibraryPreference;
|
||||||
import io.github.dsheirer.preference.directory.DirectoryPreference;
|
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.event.DecodeEventPreference;
|
||||||
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
|
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
|
||||||
import io.github.dsheirer.preference.javafx.JavaFxPreferences;
|
import io.github.dsheirer.preference.javafx.JavaFxPreferences;
|
||||||
@@ -60,7 +60,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
|||||||
private ChannelMultiFrequencyPreference mChannelMultiFrequencyPreference;
|
private ChannelMultiFrequencyPreference mChannelMultiFrequencyPreference;
|
||||||
private DecodeEventPreference mDecodeEventPreference;
|
private DecodeEventPreference mDecodeEventPreference;
|
||||||
private DirectoryPreference mDirectoryPreference;
|
private DirectoryPreference mDirectoryPreference;
|
||||||
private DuplicateCallDetectionPreference mDuplicateCallDetectionPreference;
|
private CallManagementPreference mDuplicateCallDetectionPreference;
|
||||||
private JmbeLibraryPreference mJmbeLibraryPreference;
|
private JmbeLibraryPreference mJmbeLibraryPreference;
|
||||||
private MP3Preference mMP3Preference;
|
private MP3Preference mMP3Preference;
|
||||||
private PlaybackPreference mPlaybackPreference;
|
private PlaybackPreference mPlaybackPreference;
|
||||||
@@ -208,7 +208,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
|||||||
/**
|
/**
|
||||||
* Duplicate call detection preferences
|
* Duplicate call detection preferences
|
||||||
*/
|
*/
|
||||||
public DuplicateCallDetectionPreference getDuplicateCallDetectionPreference()
|
public CallManagementPreference getDuplicateCallDetectionPreference()
|
||||||
{
|
{
|
||||||
return mDuplicateCallDetectionPreference;
|
return mDuplicateCallDetectionPreference;
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,7 @@ public class UserPreferences implements Listener<PreferenceType>
|
|||||||
mChannelMultiFrequencyPreference = new ChannelMultiFrequencyPreference(this::receive);
|
mChannelMultiFrequencyPreference = new ChannelMultiFrequencyPreference(this::receive);
|
||||||
mDecodeEventPreference = new DecodeEventPreference(this::receive);
|
mDecodeEventPreference = new DecodeEventPreference(this::receive);
|
||||||
mDirectoryPreference = new DirectoryPreference(this::receive);
|
mDirectoryPreference = new DirectoryPreference(this::receive);
|
||||||
mDuplicateCallDetectionPreference = new DuplicateCallDetectionPreference(this::receive);
|
mDuplicateCallDetectionPreference = new CallManagementPreference(this::receive);
|
||||||
mJmbeLibraryPreference = new JmbeLibraryPreference(this::receive);
|
mJmbeLibraryPreference = new JmbeLibraryPreference(this::receive);
|
||||||
mMP3Preference = new MP3Preference(this::receive);
|
mMP3Preference = new MP3Preference(this::receive);
|
||||||
mPlaybackPreference = new PlaybackPreference(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
|
* 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
|
||||||
@@ -19,38 +19,40 @@
|
|||||||
|
|
||||||
package io.github.dsheirer.preference.duplicate;
|
package io.github.dsheirer.preference.duplicate;
|
||||||
|
|
||||||
|
import io.github.dsheirer.audio.broadcast.PatchGroupStreamingOption;
|
||||||
import io.github.dsheirer.preference.Preference;
|
import io.github.dsheirer.preference.Preference;
|
||||||
import io.github.dsheirer.preference.PreferenceType;
|
import io.github.dsheirer.preference.PreferenceType;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
import java.util.prefs.Preferences;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
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_TALKGROUP = "duplicate.call.detect.talkgroup";
|
||||||
private static final String PREFERENCE_KEY_DETECT_DUPLICATE_RADIO = "duplicate.call.detect.radio";
|
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_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_RECORDING = "suppress.duplicate.audio.recording";
|
||||||
private static final String PREFERENCE_KEY_SUPPRESS_DUPLICATE_STREAMING = "suppress.duplicate.audio.streaming";
|
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 final static Logger mLog = LoggerFactory.getLogger(CallManagementPreference.class);
|
||||||
private Preferences mPreferences = Preferences.userNodeForPackage(DuplicateCallDetectionPreference.class);
|
private Preferences mPreferences = Preferences.userNodeForPackage(CallManagementPreference.class);
|
||||||
private Boolean mDuplicateCallDetectionByTalkgroupEnabled;
|
private Boolean mDuplicateCallDetectionByTalkgroupEnabled;
|
||||||
private Boolean mDuplicateCallDetectionByRadioEnabled;
|
private Boolean mDuplicateCallDetectionByRadioEnabled;
|
||||||
private Boolean mDuplicatePlaybackSuppressionEnabled;
|
private Boolean mDuplicatePlaybackSuppressionEnabled;
|
||||||
private Boolean mDuplicateRecordingSuppressionEnabled;
|
private Boolean mDuplicateRecordingSuppressionEnabled;
|
||||||
private Boolean mDuplicateStreamingSuppressionEnabled;
|
private Boolean mDuplicateStreamingSuppressionEnabled;
|
||||||
|
private PatchGroupStreamingOption mPatchGroupStreamingOption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an instance
|
* Constructs an instance
|
||||||
* @param updateListener to receive notifications that a preference has been updated
|
* @param updateListener to receive notifications that a preference has been updated
|
||||||
*/
|
*/
|
||||||
public DuplicateCallDetectionPreference(Listener<PreferenceType> updateListener)
|
public CallManagementPreference(Listener<PreferenceType> updateListener)
|
||||||
{
|
{
|
||||||
super(updateListener);
|
super(updateListener);
|
||||||
}
|
}
|
||||||
@@ -182,6 +184,51 @@ public class DuplicateCallDetectionPreference extends Preference
|
|||||||
{
|
{
|
||||||
mPreferences.putBoolean(PREFERENCE_KEY_SUPPRESS_DUPLICATE_STREAMING, enabled);
|
mPreferences.putBoolean(PREFERENCE_KEY_SUPPRESS_DUPLICATE_STREAMING, enabled);
|
||||||
mDuplicateStreamingSuppressionEnabled = 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
|
* 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
|
||||||
@@ -24,6 +24,7 @@ import io.github.dsheirer.audio.AudioSegment;
|
|||||||
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.preference.UserPreferences;
|
import io.github.dsheirer.preference.UserPreferences;
|
||||||
import io.github.dsheirer.record.wave.AudioMetadata;
|
import io.github.dsheirer.record.wave.AudioMetadata;
|
||||||
import io.github.dsheirer.record.wave.AudioMetadataUtils;
|
import io.github.dsheirer.record.wave.AudioMetadataUtils;
|
||||||
@@ -58,14 +59,28 @@ public class AudioSegmentRecorder
|
|||||||
*/
|
*/
|
||||||
public static void record(AudioSegment audioSegment, Path path, RecordFormat recordFormat,
|
public static void record(AudioSegment audioSegment, Path path, RecordFormat recordFormat,
|
||||||
UserPreferences userPreferences) throws IOException
|
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)
|
switch(recordFormat)
|
||||||
{
|
{
|
||||||
case MP3:
|
case MP3:
|
||||||
recordMP3(audioSegment, path, userPreferences);
|
recordMP3(audioSegment, path, userPreferences, identifierCollection);
|
||||||
break;
|
break;
|
||||||
case WAVE:
|
case WAVE:
|
||||||
recordWAVE(audioSegment, path);
|
recordWAVE(audioSegment, path, identifierCollection);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unrecognized recording format [" + recordFormat.name() + "]");
|
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.
|
* Records the audio segment as an MP3 file to the specified path.
|
||||||
* @param audioSegment to record
|
* @param audioSegment to record
|
||||||
* @param path for the recording
|
* @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
|
* @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())
|
if(audioSegment.hasAudio())
|
||||||
{
|
{
|
||||||
OutputStream outputStream = new FileOutputStream(path.toFile());
|
OutputStream outputStream = new FileOutputStream(path.toFile());
|
||||||
|
|
||||||
//Write ID3 metadata
|
//Write ID3 metadata
|
||||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(audioSegment.getIdentifierCollection(),
|
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(identifierCollection,
|
||||||
audioSegment.getAliasList());
|
audioSegment.getAliasList());
|
||||||
|
|
||||||
byte[] id3Bytes = AudioMetadataUtils.getMP3ID3(metadataMap);
|
byte[] id3Bytes = AudioMetadataUtils.getMP3ID3(metadataMap);
|
||||||
@@ -123,9 +141,10 @@ public class AudioSegmentRecorder
|
|||||||
* Records the audio segment as a WAVe file to the specified path.
|
* Records the audio segment as a WAVe file to the specified path.
|
||||||
* @param audioSegment to record
|
* @param audioSegment to record
|
||||||
* @param path for the recording
|
* @param path for the recording
|
||||||
|
* @param identifierCollection to use instead of the audioSegment's embedded identifier collection
|
||||||
* @throws IOException on any errors
|
* @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())
|
if(audioSegment.hasAudio())
|
||||||
{
|
{
|
||||||
@@ -136,7 +155,7 @@ public class AudioSegmentRecorder
|
|||||||
writer.writeData(ConversionUtils.convertToSigned16BitSamples(audioBuffer));
|
writer.writeData(ConversionUtils.convertToSigned16BitSamples(audioBuffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(audioSegment.getIdentifierCollection(),
|
Map<AudioMetadata,String> metadataMap = AudioMetadataUtils.getMetadataMap(identifierCollection,
|
||||||
audioSegment.getAliasList());
|
audioSegment.getAliasList());
|
||||||
|
|
||||||
ByteBuffer listChunk = AudioMetadataUtils.getLISTChunk(metadataMap);
|
ByteBuffer listChunk = AudioMetadataUtils.getLISTChunk(metadataMap);
|
||||||
|
|||||||
Reference in New Issue
Block a user