#1994 P25 Phase1 missing subsequent calls audio when multiple conversations on the same traffic channel. (#1995)

Fixed issue where sdrtrunk was not checking HDU and LDU2 encryption sequences as valid before assessing the encryption state of a call.  Updated P25P1 audio module to check the valid flag for both the HDU and the LDU2 encryption segment before assigning encryption state.  Now caches all LDU messages until encryption state is determined.

Co-authored-by: Dennis Sheirer <dsheirer@github.com>
This commit is contained in:
Denny Sheirer
2024-09-29 07:53:13 -04:00
committed by GitHub
parent 32ce79b8af
commit 0ecdf4dd2b
8 changed files with 157 additions and 40 deletions

View File

@@ -19,11 +19,11 @@
package io.github.dsheirer.gui.viewer;
import io.github.dsheirer.audio.AudioSegment;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.controller.channel.event.ChannelStartProcessingRequest;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.event.DecodeEventSnapshot;
import io.github.dsheirer.module.decode.event.IDecodeEvent;
import java.util.ArrayList;
import java.util.List;
@@ -37,6 +37,7 @@ public class MessagePackage
private List<DecoderStateEvent> mDecoderStateEvents = new ArrayList<>();
private List<DecodeEventSnapshot> mDecodeEvents = new ArrayList<>();
private ChannelStartProcessingRequest mChannelStartProcessingRequest;
private AudioSegment mAudioSegment;
/**
* Constructs an instance
@@ -152,8 +153,39 @@ public class MessagePackage
return mChannelStartProcessingRequest == null ? 0 : 1;
}
/**
* Count (0 or 1) of audio segment.
*/
public int getAudioSegmentCount()
{
return mAudioSegment == null ? 0 : 1;
}
public ChannelStartProcessingRequest getChannelStartProcessingRequest()
{
return mChannelStartProcessingRequest;
}
/**
* Generated audio segment.
* @return segment or null.
*/
public AudioSegment getAudioSegment()
{
return mAudioSegment;
}
/**
* Adds the audio segment to the package
* @param audioSegment to add
*/
public void add(AudioSegment audioSegment)
{
if(mAudioSegment != null)
{
throw new IllegalStateException("AudioSegment already set");
}
mAudioSegment = audioSegment;
}
}

View File

@@ -22,6 +22,8 @@ package io.github.dsheirer.gui.viewer;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.module.decode.event.DecodeEventSnapshot;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
@@ -38,6 +40,7 @@ public class MessagePackageViewer extends VBox
private TableView<DecoderStateEvent> mDecoderStateEventTableView;
private TableView<DecodeEventSnapshot> mDecodeEventTableView;
private IdentifierCollectionViewer mIdentifierCollectionViewer;
private IdentifierCollectionViewer mAudioSegmentIdCollectionViewer;
private ChannelStartProcessingRequestViewer mChannelStartProcessingRequestViewer;
/**
@@ -63,8 +66,14 @@ public class MessagePackageViewer extends VBox
GridPane.setHgrow(getDecodeEventTableView(), Priority.ALWAYS);
gridPane.add(getDecodeEventTableView(), 1, 2);
gridPane.add(new Label("Channel Start Processing Request"), 0, 3);
gridPane.add(getChannelStartProcessingRequestViewer(), 0, 4);
TabPane tabPane = new TabPane();
Tab startTab = new Tab("Channel Start Processing Request");
startTab.setContent(getChannelStartProcessingRequestViewer());
Tab audioTab = new Tab("Audio Segment");
audioTab.setContent(getAudioSegmentIdCollectionViewer());
tabPane.getTabs().addAll(audioTab, startTab);
gridPane.add(tabPane, 0, 4);
getIdentifierCollectionViewer().setPrefHeight(120);
gridPane.add(new Label("Selected Decode Event Identifiers"), 1, 3);
@@ -96,6 +105,15 @@ public class MessagePackageViewer extends VBox
{
getDecodeEventTableView().getSelectionModel().select(0);
}
if(messagePackage.getAudioSegment() != null)
{
getAudioSegmentIdCollectionViewer().set(messagePackage.getAudioSegment().getIdentifierCollection());
}
else
{
getAudioSegmentIdCollectionViewer().set(null);
}
}
}
@@ -109,6 +127,16 @@ public class MessagePackageViewer extends VBox
return mIdentifierCollectionViewer;
}
private IdentifierCollectionViewer getAudioSegmentIdCollectionViewer()
{
if(mAudioSegmentIdCollectionViewer == null)
{
mAudioSegmentIdCollectionViewer = new IdentifierCollectionViewer();
}
return mAudioSegmentIdCollectionViewer;
}
private Label getMessageLabel()
{
if(mMessageLabel == null)

View File

@@ -20,13 +20,13 @@
package io.github.dsheirer.gui.viewer;
import com.google.common.eventbus.Subscribe;
import io.github.dsheirer.audio.AudioSegment;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.controller.channel.event.ChannelStartProcessingRequest;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.decode.event.DecodeEvent;
import io.github.dsheirer.module.decode.event.DecodeEventSnapshot;
import io.github.dsheirer.module.decode.event.IDecodeEvent;
import io.github.dsheirer.module.decode.event.IDecodeEventListener;
/**
* Utility for combining a message and decoder state events.
@@ -42,6 +42,18 @@ public class MessagePackager
{
}
/**
* Adds an audio segment.
* @param audioSegment to add
*/
public void add(AudioSegment audioSegment)
{
if(mMessagePackage != null)
{
mMessagePackage.add(audioSegment);
}
}
/**
* Adds the message and creates a new MessageWithEvents instance, wrapping the message, ready to also receive any
* decode events and decoder state events. The previous message with events is overwritten.

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.gui.viewer;
import io.github.dsheirer.preference.UserPreferences;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Node;
@@ -51,6 +52,7 @@ public class MessageRecordingViewer extends VBox
private int mTabCounterDmr = 1;
private int mTabCounterP25P1 = 1;
private int mTabCounterP25P2 = 1;
private UserPreferences mUserPreferences = new UserPreferences();
/**
* Constructs an instance
@@ -77,7 +79,7 @@ public class MessageRecordingViewer extends VBox
});
MenuItem p25p1MenuItem = new MenuItem("P25 Phase 1");
p25p1MenuItem.onActionProperty().set(event -> {
Tab tab = new LabeledTab("P25P1-" + mTabCounterP25P1++, new P25P1Viewer());
Tab tab = new LabeledTab("P25P1-" + mTabCounterP25P1++, new P25P1Viewer(mUserPreferences));
getTabPane().getTabs().add(tab);
getTabPane().getSelectionModel().select(tab);
});
@@ -108,7 +110,7 @@ public class MessageRecordingViewer extends VBox
mTabPane = new TabPane();
mTabPane.setMaxHeight(Double.MAX_VALUE);
mTabPane.getTabs().add(new LabeledTab("DMR-" + mTabCounterDmr++, new DmrViewer()));
mTabPane.getTabs().add(new LabeledTab("P25P1-" + mTabCounterP25P1++, new P25P1Viewer()));
mTabPane.getTabs().add(new LabeledTab("P25P1-" + mTabCounterP25P1++, new P25P1Viewer(mUserPreferences)));
mTabPane.getTabs().add(new LabeledTab("P25P2-" + mTabCounterP25P2++, new P25P2Viewer()));
}

View File

@@ -20,16 +20,24 @@
package io.github.dsheirer.gui.viewer;
import com.google.common.eventbus.EventBus;
import io.github.dsheirer.alias.AliasList;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.channel.state.SingleChannelState;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.identifier.IdentifierUpdateNotification;
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.message.StuffBitsMessage;
import io.github.dsheirer.module.decode.p25.P25TrafficChannelManager;
import io.github.dsheirer.module.decode.p25.audio.P25P1AudioModule;
import io.github.dsheirer.module.decode.p25.phase1.DecodeConfigP25Phase1;
import io.github.dsheirer.module.decode.p25.phase1.P25P1DecoderState;
import io.github.dsheirer.module.decode.p25.phase1.P25P1MessageFramer;
import io.github.dsheirer.module.decode.p25.phase1.P25P1MessageProcessor;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.record.binary.BinaryReader;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.util.ThreadPool;
import java.io.File;
import java.nio.ByteBuffer;
@@ -94,9 +102,11 @@ public class P25P1Viewer extends VBox
private ProgressIndicator mLoadingIndicator;
private MessagePackageViewer mMessagePackageViewer;
private StringProperty mLoadedFile = new SimpleStringProperty();
private UserPreferences mUserPreferences;
public P25P1Viewer()
public P25P1Viewer(UserPreferences userPreferences)
{
mUserPreferences = userPreferences;
setPadding(new Insets(5));
setSpacing(5);
@@ -155,7 +165,9 @@ public class P25P1Viewer extends VBox
List<MessagePackage> messagePackages = new ArrayList<>();
P25P1MessageFramer messageFramer = new P25P1MessageFramer(null, 9600);
P25P1MessageProcessor messageProcessor = new P25P1MessageProcessor();
messageFramer.setListener(messageProcessor);
Broadcaster<IMessage> messageBroadcaster = new Broadcaster<>();
messageFramer.setListener(messageBroadcaster);
messageBroadcaster.addListener(messageProcessor);
Channel empty = new Channel("Empty");
empty.setDecodeConfiguration(new DecodeConfigP25Phase1());
@@ -169,10 +181,14 @@ public class P25P1Viewer extends VBox
trafficChannelManager.setInterModuleEventBus(eventBus);
//Register to receive events
trafficChannelManager.addDecodeEventListener(decodeEvent -> messagePackager.add(decodeEvent));
trafficChannelManager.addDecodeEventListener(messagePackager::add);
P25P1DecoderState decoderState = new P25P1DecoderState(empty, trafficChannelManager);
decoderState.setDecoderStateListener(decoderStateEvent -> messagePackager.add(decoderStateEvent));
decoderState.addDecodeEventListener(decodeEvent -> messagePackager.add(decodeEvent));
Broadcaster<DecoderStateEvent> decoderStateEventBroadcaster = new Broadcaster<>();
decoderState.setDecoderStateListener(decoderStateEventBroadcaster);
decoderStateEventBroadcaster.addListener(messagePackager::add);
decoderState.addDecodeEventListener(messagePackager::add);
decoderState.start();
long frequency = getFrequencyFromFile(mLoadedFile.get());
@@ -197,6 +213,16 @@ public class P25P1Viewer extends VBox
}
});
P25P1AudioModule audioModule = new P25P1AudioModule(mUserPreferences, new AliasList("debug"));
decoderState.setIdentifierUpdateListener(audioModule.getIdentifierUpdateListener());
audioModule.setAudioSegmentListener(messagePackager::add);
messageBroadcaster.addListener(audioModule);
audioModule.start();
SingleChannelState singleChannelState = new SingleChannelState(empty, new AliasModel());
singleChannelState.setSquelchStateListener(squelchStateEvent -> audioModule.getSquelchStateListener().receive(squelchStateEvent));
decoderStateEventBroadcaster.addListener(singleChannelState.getDecoderStateListener());
singleChannelState.start();
try(BinaryReader reader = new BinaryReader(file.toPath(), 200))
{
while(reader.hasNext())
@@ -210,6 +236,10 @@ public class P25P1Viewer extends VBox
ioe.printStackTrace();
}
audioModule.stop();
decoderState.stop();
singleChannelState.stop();
Platform.runLater(() -> {
getLoadingIndicator().setVisible(false);
getSelectedFileLabel().setText(file.getName());
@@ -444,8 +474,13 @@ public class P25P1Viewer extends VBox
channelStartCountColumn.setText("Starts");
channelStartCountColumn.setCellValueFactory(new PropertyValueFactory<>("channelStartProcessingRequestCount"));
TableColumn audioSegmentCountColumn = new TableColumn();
audioSegmentCountColumn.setPrefWidth(50);
audioSegmentCountColumn.setText("Audio");
audioSegmentCountColumn.setCellValueFactory(new PropertyValueFactory<>("audioSegmentCount"));
mMessagePackageTableView.getColumns().addAll(timestampColumn, validColumn, timeslotColumn, messageColumn,
decodeEventCountColumn, decoderStateEventCountColumn, channelStartCountColumn);
decodeEventCountColumn, decoderStateEventCountColumn, channelStartCountColumn, audioSegmentCountColumn);
}
return mMessagePackageTableView;