P25 - adds audio muting (ignore) for encrypted p25 voice calls

This commit is contained in:
dennis.sheirer
2015-04-04 12:32:18 +00:00
parent fc8f2772ae
commit f9d139a807
8 changed files with 153 additions and 122 deletions

View File

@@ -230,6 +230,7 @@ public abstract class CallEvent
DATA_CALL( "Data Call" ),
DEREGISTER( "Deregister" ),
EMERGENCY( "EMERGENCY" ),
ENCRYPTED_CALL( "Encrypted Call" ),
FUNCTION( "Function" ),
GPS( "GPS" ),
ID_ANI( "ANI" ),

View File

@@ -223,23 +223,34 @@ public class P25ChannelState extends ChannelState
private void processHDU( HDUMessage hdu )
{
State state = State.CALL;
if( hdu.isValid() && hdu.isEncrypted() )
{
state = State.ENCRYPTED;
}
if( isActiveCall( mCurrentChannel, hdu.getToID() ) )
{
updateCall( State.CALL, mCurrentChannel, null, hdu.getTalkgroupID() );
updateCall( state, mCurrentChannel, null, hdu.getTalkgroupID() );
}
else
{
StringBuilder sb = new StringBuilder();
if( hdu.getEncryption() != Encryption.UNENCRYPTED )
CallEventType type = CallEventType.CALL;
if( hdu.isValid() && hdu.isEncrypted() )
{
type = CallEventType.ENCRYPTED_CALL;
sb.append( "ENCRYPTED WITH " );
sb.append( hdu.getEncryption().name() );
sb.append( " KEY:" );
sb.append( hdu.getKeyID() );
}
P25CallEvent event = new P25CallEvent.Builder( CallEventType.CALL )
P25CallEvent event = new P25CallEvent.Builder( type )
.aliasList( mAliasList )
.channel( mCurrentChannel )
.frequency( mCurrentChannelFrequency )
@@ -815,6 +826,14 @@ public class P25ChannelState extends ChannelState
mAudioOutput.receive( ldu );
}
State state = getState();
/* Only change the state for valid ldus */
if( ldu.isValid() )
{
state = ldu.isEncrypted() ? State.ENCRYPTED : State.CALL;
}
if( ldu instanceof LDU1Message )
{
switch( ((LDU1Message)ldu).getOpcode() )
@@ -836,7 +855,7 @@ public class P25ChannelState extends ChannelState
break;
case ADJACENT_SITE_STATUS_BROADCAST_EXPLICIT:
/* This message doesn't provide anything we need for channel state */
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case CALL_ALERT:
if( ldu instanceof decode.p25.message.ldu.lc.CallAlert )
@@ -870,12 +889,12 @@ public class P25ChannelState extends ChannelState
case CHANNEL_IDENTIFIER_UPDATE:
/* This message is handled by the P25MessageProcessor and
* inserted into any channels needing frequency band info */
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case CHANNEL_IDENTIFIER_UPDATE_EXPLICIT:
/* This message is handled by the P25MessageProcessor and
* inserted into any channels needing frequency band info */
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case EXTENDED_FUNCTION_COMMAND:
if( ldu instanceof decode.p25.message.ldu.lc.ExtendedFunctionCommand )
@@ -895,7 +914,7 @@ public class P25ChannelState extends ChannelState
{
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case GROUP_AFFILIATION_QUERY:
if( ldu instanceof decode.p25.message.ldu.lc.GroupAffiliationQuery )
@@ -914,7 +933,7 @@ public class P25ChannelState extends ChannelState
{
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case GROUP_VOICE_CHANNEL_UPDATE:
if( ldu instanceof decode.p25.message.ldu.lc.GroupVoiceChannelUpdate )
@@ -925,7 +944,7 @@ public class P25ChannelState extends ChannelState
if( isActiveCall( gvcu.getChannelA(),
gvcu.getGroupAddressA() ) )
{
updateCall( State.CALL,
updateCall( state,
gvcu.getChannelA(),
gvcu.getGroupAddressA(),
gvcu.getGroupAddressB() );
@@ -959,7 +978,7 @@ public class P25ChannelState extends ChannelState
if( isActiveCall( gvcue.getTransmitChannel(),
gvcue.getGroupAddress() ) )
{
updateCall( State.CALL,
updateCall( state,
gvcue.getTransmitChannel(),
null,
gvcue.getGroupAddress() );
@@ -991,7 +1010,7 @@ public class P25ChannelState extends ChannelState
if( isActiveCall( mCurrentChannel, gvcuser.getGroupAddress() ) )
{
updateCall( State.CALL,
updateCall( state,
mCurrentChannel,
gvcuser.getSourceAddress(),
gvcuser.getGroupAddress() );
@@ -1036,7 +1055,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case NETWORK_STATUS_BROADCAST:
if( ldu instanceof decode.p25.message.ldu.lc.NetworkStatusBroadcast )
@@ -1048,7 +1067,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case NETWORK_STATUS_BROADCAST_EXPLICIT:
if( ldu instanceof decode.p25.message.ldu.lc.NetworkStatusBroadcastExplicit )
@@ -1060,7 +1079,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case PROTECTION_PARAMETER_BROADCAST:
if( ldu instanceof decode.p25.message.ldu.lc.ProtectionParameterBroadcast )
@@ -1082,7 +1101,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case RFSS_STATUS_BROADCAST:
if( ldu instanceof decode.p25.message.ldu.lc.RFSSStatusBroadcast )
@@ -1096,20 +1115,13 @@ public class P25ChannelState extends ChannelState
rfsssb.getSiteID();
updateSite( site );
// if( mCurrentChannel == null ||
// !mCurrentChannel.contentEquals( rfsssb.getChannel() ) )
// {
// mCurrentChannel = rfsssb.getChannel();
// mCurrentChannelFrequency = rfsssb.getDownlinkFrequency();
// }
}
else
{
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case RFSS_STATUS_BROADCAST_EXPLICIT:
if( ldu instanceof decode.p25.message.ldu.lc.RFSSStatusBroadcastExplicit )
@@ -1121,20 +1133,13 @@ public class P25ChannelState extends ChannelState
rfsssbe.getSiteID();
updateSite( site );
// if( mCurrentChannel == null ||
// !mCurrentChannel.contentEquals( rfsssbe.getTransmitChannel() ) )
// {
// mCurrentChannel = rfsssbe.getTransmitChannel();
// mCurrentChannelFrequency = rfsssbe.getDownlinkFrequency();
// }
}
else
{
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case SECONDARY_CONTROL_CHANNEL_BROADCAST:
if( ldu instanceof decode.p25.message.ldu.lc.SecondaryControlChannelBroadcast )
@@ -1152,7 +1157,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case SECONDARY_CONTROL_CHANNEL_BROADCAST_EXPLICIT:
if( ldu instanceof decode.p25.message.ldu.lc.SecondaryControlChannelBroadcastExplicit )
@@ -1170,7 +1175,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case STATUS_QUERY:
if( ldu instanceof decode.p25.message.ldu.lc.StatusQuery )
@@ -1191,7 +1196,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case STATUS_UPDATE:
if( ldu instanceof decode.p25.message.ldu.lc.StatusUpdate )
@@ -1213,12 +1218,12 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case SYSTEM_SERVICE_BROADCAST:
/* This message doesn't provide anything we need for channel state */
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case TELEPHONE_INTERCONNECT_ANSWER_REQUEST:
if( ldu instanceof decode.p25.message.ldu.lc.TelephoneInterconnectAnswerRequest )
@@ -1239,7 +1244,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case TELEPHONE_INTERCONNECT_VOICE_CHANNEL_USER:
if( ldu instanceof TelephoneInterconnectVoiceChannelUser )
@@ -1249,7 +1254,7 @@ public class P25ChannelState extends ChannelState
if( isActiveCall( mCurrentChannel, tivcu.getAddress() ) )
{
updateCall( State.CALL,
updateCall( state,
mCurrentChannel,
null,
tivcu.getAddress() );
@@ -1294,7 +1299,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case UNIT_REGISTRATION_COMMAND:
if( ldu instanceof decode.p25.message.ldu.lc.UnitRegistrationCommand )
@@ -1314,7 +1319,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case UNIT_TO_UNIT_ANSWER_REQUEST:
if( ldu instanceof decode.p25.message.ldu.lc.UnitToUnitAnswerRequest )
@@ -1335,7 +1340,7 @@ public class P25ChannelState extends ChannelState
logAlternateVendorMessage( ldu );
}
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
break;
case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
if( ldu instanceof UnitToUnitVoiceChannelUser )
@@ -1345,7 +1350,7 @@ public class P25ChannelState extends ChannelState
if( isActiveCall( mCurrentChannel, uuvcu.getTargetAddress() ) )
{
updateCall( State.CALL,
updateCall( state,
mCurrentChannel,
uuvcu.getSourceAddress(),
uuvcu.getTargetAddress() );
@@ -1378,7 +1383,7 @@ public class P25ChannelState extends ChannelState
else
{
//LDU2
updateCall( State.CALL, mCurrentChannel, null, null );
updateCall( state, mCurrentChannel, null, null );
}
}

View File

@@ -48,14 +48,15 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
private AudioInputStream mIMBEToPCMConverter;
// private AudioInputStream mUpsampler;
private ArrayBlockingQueue<byte[]> mIMBEFrameQueue =
new ArrayBlockingQueue<byte[]>( 100 );
new ArrayBlockingQueue<byte[]>( 200 );
private ArrayBlockingQueue<byte[]> mProcessedAudioQueue =
new ArrayBlockingQueue<byte[]>( 100 );
new ArrayBlockingQueue<byte[]>( 200 );
private AtomicBoolean mConverting = new AtomicBoolean();
private AtomicBoolean mDispatching = new AtomicBoolean();
private AtomicBoolean mEnabled = new AtomicBoolean();
private boolean mCanProcessAudio = false;
private boolean mEncryptedAudio = false;
private ThreadPoolManager mThreadPoolManager;
@@ -85,14 +86,26 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
{
if( message instanceof LDUMessage )
{
for( byte[] frame: ((LDUMessage)message).getIMBEFrames() )
LDUMessage ldu = (LDUMessage)message;
/* Check valid ldu frames for encryption. Set state to encrypted
* so that no encrypted frames are sent to the converter */
if( ldu.isValid() )
{
if( !mIMBEFrameQueue.offer( frame ) )
mEncryptedAudio = ldu.isEncrypted();
}
if( !mEncryptedAudio )
{
for( byte[] frame: ((LDUMessage)message).getIMBEFrames() )
{
mLog.debug( "IMBE frame queue full - throwing away imbe audio frame" );
if( !mIMBEFrameQueue.offer( frame ) )
{
mLog.debug( "IMBE frame queue full - throwing away "
+ "imbe audio frame" );
}
}
}
}
}
}
@@ -128,56 +141,41 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
if( mIMBEToPCMConverter != null )
{
mLog.debug( "IMBE audio converter library loaded successfully" );
// mUpsampler = AudioSystem
// .getAudioInputStream( IMBEAudioFormat.PCM_SIGNED_48KHZ_16BITS,
// mIMBEToPCMConverter );
//
// if( mUpsampler != null )
// {
// mLog.debug( "Resampler loaded successfully" );
try
{
mOutput = AudioSystem.getSourceDataLine( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS );
try
{
mOutput = AudioSystem.getSourceDataLine( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS );
if( mOutput != null )
if( mOutput != null )
{
mLog.debug( "Audio output line loaded successfully" );
/* Open the audio line with room for two buffers */
mOutput.open( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS,
PROCESSED_AUDIO_FRAME_SIZE * 2 );
Control[] controls = mOutput.getControls();
FloatControl gain = (FloatControl)mOutput
.getControl( FloatControl.Type.MASTER_GAIN );
if( gain != null )
{
mLog.debug( "Audio output line loaded successfully" );
/* Open the audio line with room for two buffers */
mOutput.open( IMBEAudioFormat.PCM_SIGNED_8KHZ_16BITS,
PROCESSED_AUDIO_FRAME_SIZE * 2 );
Control[] controls = mOutput.getControls();
FloatControl gain = (FloatControl)mOutput
.getControl( FloatControl.Type.MASTER_GAIN );
if( gain != null )
{
// gain.setValue( 4.0f );
}
mCanProcessAudio = true;
gain.setValue( 2.0f );
}
else
{
mLog.debug( "Couldn't create output line" );
}
}
catch ( LineUnavailableException e )
mCanProcessAudio = true;
}
else
{
mLog.error( "AudioOutput - couldn't open audio speakers "
+ "for playback", e );
mLog.debug( "Couldn't create output line" );
}
// }
// else
// {
// mIMBEToPCMConverter = null;
//
// mLog.debug( "couldn't load Resampler" );
// }
}
catch ( LineUnavailableException e )
{
mLog.error( "AudioOutput - couldn't open audio speakers "
+ "for playback", e );
}
}
else
{
@@ -256,8 +254,6 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener,
try
{
// mLog.debug( "reading converted audio bytes - available: " + mUpsampler.available() );
// int read = mUpsampler.read( audio );
int read = mIMBEToPCMConverter.read( audio );
if( read > 0 )

View File

@@ -244,6 +244,11 @@ public class HDUMessage extends P25Message
return Encryption.fromValue( mMessage.getInt( ALGORITHM_ID ) );
}
public boolean isEncrypted()
{
return getEncryption() != Encryption.UNENCRYPTED;
}
public int getKeyID()
{
return mMessage.getInt( KEY_ID );

View File

@@ -17,15 +17,6 @@ public class LDU1Message extends LDUMessage
public static final int[] OPCODE = { 354,355,356,357,362,363 };
public static final int[] VENDOR = { 364,365,366,367,372,373,374,375 };
// public static final int[] OCTET_1 = { 364,365,366,367,372,373,374,375 };
// public static final int[] OCTET_2 = { 376,377,382,383,384,385,386,387 };
// public static final int[] OCTET_3 = { 536,537,538,539,540,541,546,547 };
// public static final int[] OCTET_4 = { 548,549,550,551,556,557,558,559 };
// public static final int[] OCTET_5 = { 560,561,566,567,568,569,570,571 };
// public static final int[] OCTET_6 = { 720,721,722,723,724,725,730,731 };
// public static final int[] OCTET_7 = { 732,733,734,735,740,741,742,743 };
// public static final int[] OCTET_8 = { 744,745,750,751,752,753,754,755 };
public static final int[] GOLAY_WORD_STARTS = {
352,362,372,382,536,546,556,566,720,730,740,750,904,914,924,934,1088,
1098,1108,1118,1272,1282,1292,1302 };
@@ -83,8 +74,13 @@ public class LDU1Message extends LDUMessage
mCRC = message.mCRC;
}
@Override
public boolean isEncrypted()
{
return mMessage.get( ENCRYPTION_FLAG );
}
private void checkCRC()
{
mCRC[ 1 ] = CRC.PASSED;
@@ -215,11 +211,6 @@ public class LDU1Message extends LDUMessage
return sb.toString();
}
public boolean isEncrypted()
{
return mMessage.get( ENCRYPTION_FLAG );
}
public boolean isImplicitFormat()
{
return mMessage.get( IMPLICIT_VENDOR_FLAG );

View File

@@ -72,6 +72,12 @@ public class LDU2Message extends LDUMessage
checkCRC();
}
@Override
public boolean isEncrypted()
{
return getEncryption() != Encryption.UNENCRYPTED;
}
private void checkCRC()
{
mCRC[ 1 ] = CRC.PASSED;

View File

@@ -10,9 +10,8 @@ import alias.AliasList;
import bits.BinaryMessage;
import decode.p25.message.P25Message;
import decode.p25.reference.DataUnitID;
import edac.CRC;
public class LDUMessage extends P25Message
public abstract class LDUMessage extends P25Message
{
private final static Logger mLog = LoggerFactory.getLogger( LDUMessage.class );
@@ -33,15 +32,10 @@ public class LDUMessage extends P25Message
AliasList aliasList )
{
super( message, duid, aliasList );
/* NID CRC is checked in the message framer, thus a constructed message
* means it passed the CRC */
//TODO: update crc status for voice frames
mCRC = new CRC[ 2 ];
mCRC[ 0 ] = CRC.PASSED;
}
public abstract boolean isEncrypted();
@Override
public String getMessage()
{

View File

@@ -25,7 +25,10 @@ import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -65,6 +68,8 @@ public class SDRTrunk
private ControllerPanel mControllerPanel;
private SpectralDisplayPanel mSpectralPanel;
private JFrame mMainGui = new JFrame();
private String mTitle;
public SDRTrunk()
{
@@ -103,6 +108,8 @@ public class SDRTrunk
/* Log any available audio converter plugins */
logAvailableAudioPlugins();
mTitle = getTitle();
//Initialize the GUI
initGUI();
@@ -159,7 +166,7 @@ public class SDRTrunk
/**
* Setup main JFrame window
*/
mMainGui.setTitle( "SDRTrunk" );
mMainGui.setTitle( mTitle );
mMainGui.setBounds( 100, 100, 1280, 800 );
mMainGui.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
@@ -170,11 +177,11 @@ public class SDRTrunk
{
if( tuner != null )
{
mMainGui.setTitle( "SDRTrunk - " + tuner.getName() );
mMainGui.setTitle( mTitle + " - " + tuner.getName() );
}
else
{
mMainGui.setTitle( "SDRTrunk" );
mMainGui.setTitle( mTitle );
}
}
} );
@@ -392,4 +399,30 @@ public class SDRTrunk
mLog.info( "Available Audio Converter: " + it.next().getClass() );
}
}
private String getTitle()
{
StringBuilder sb = new StringBuilder();
sb.append( "SDRTrunk" );
try( BufferedReader reader = new BufferedReader(
new InputStreamReader( this.getClass()
.getResourceAsStream( "/sdrtrunk-version" ) ) ) )
{
String version = reader.readLine();
if( version != null )
{
sb.append( " V" );
sb.append( version );
}
}
catch( Exception e )
{
mLog.error( "Couldn't read sdrtrunk version from application jar file" );
}
return sb.toString();
}
}