diff --git a/src/controller/activity/CallEvent.java b/src/controller/activity/CallEvent.java index 61dd9a5b..84e854f2 100644 --- a/src/controller/activity/CallEvent.java +++ b/src/controller/activity/CallEvent.java @@ -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" ), diff --git a/src/decode/p25/P25ChannelState.java b/src/decode/p25/P25ChannelState.java index 7c7a86c8..f7730ceb 100644 --- a/src/decode/p25/P25ChannelState.java +++ b/src/decode/p25/P25ChannelState.java @@ -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 ); } } diff --git a/src/decode/p25/audio/P25AudioOutput.java b/src/decode/p25/audio/P25AudioOutput.java index 728e7d50..7489a83f 100644 --- a/src/decode/p25/audio/P25AudioOutput.java +++ b/src/decode/p25/audio/P25AudioOutput.java @@ -48,14 +48,15 @@ public class P25AudioOutput implements IAudioOutput, IAudioTypeListener, private AudioInputStream mIMBEToPCMConverter; // private AudioInputStream mUpsampler; private ArrayBlockingQueue mIMBEFrameQueue = - new ArrayBlockingQueue( 100 ); + new ArrayBlockingQueue( 200 ); private ArrayBlockingQueue mProcessedAudioQueue = - new ArrayBlockingQueue( 100 ); + new ArrayBlockingQueue( 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 ) diff --git a/src/decode/p25/message/hdu/HDUMessage.java b/src/decode/p25/message/hdu/HDUMessage.java index 5094e2d4..857658f2 100644 --- a/src/decode/p25/message/hdu/HDUMessage.java +++ b/src/decode/p25/message/hdu/HDUMessage.java @@ -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 ); diff --git a/src/decode/p25/message/ldu/LDU1Message.java b/src/decode/p25/message/ldu/LDU1Message.java index 34364b1e..c1997626 100644 --- a/src/decode/p25/message/ldu/LDU1Message.java +++ b/src/decode/p25/message/ldu/LDU1Message.java @@ -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 ); diff --git a/src/decode/p25/message/ldu/LDU2Message.java b/src/decode/p25/message/ldu/LDU2Message.java index 64d37c31..946061fd 100644 --- a/src/decode/p25/message/ldu/LDU2Message.java +++ b/src/decode/p25/message/ldu/LDU2Message.java @@ -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; diff --git a/src/decode/p25/message/ldu/LDUMessage.java b/src/decode/p25/message/ldu/LDUMessage.java index 66a0df80..cb8c432c 100644 --- a/src/decode/p25/message/ldu/LDUMessage.java +++ b/src/decode/p25/message/ldu/LDUMessage.java @@ -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() { diff --git a/src/gui/SDRTrunk.java b/src/gui/SDRTrunk.java index b9b5e3ce..ac68ea20 100644 --- a/src/gui/SDRTrunk.java +++ b/src/gui/SDRTrunk.java @@ -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(); + } }