From d466ec9f5eac2c99767ddba1a30b4c9e9d5f452d Mon Sep 17 00:00:00 2001 From: Denny Date: Sun, 21 Aug 2016 07:21:38 -0400 Subject: [PATCH] Changes audio module decimation filter from lowpass to bandpass so that we can remove 0-250 Hz and any LTR signalling from the audio output. --- src/audio/AudioModule.java | 24 +- src/dsp/filter/design/FilterViewer.java | 50 +- .../PolyphaseFIRDecimatingFilter_RB.java | 10 +- .../decode/ltrnet/LTRNetDecoderState.java | 1388 +++++++++-------- .../decode/p25/audio/P25AudioModule.java | 8 +- 5 files changed, 745 insertions(+), 735 deletions(-) diff --git a/src/audio/AudioModule.java b/src/audio/AudioModule.java index b89f493d..4a02298f 100644 --- a/src/audio/AudioModule.java +++ b/src/audio/AudioModule.java @@ -46,15 +46,15 @@ public class AudioModule extends Module implements IAudioPacketProvider, static { - FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() - .sampleRate(48000) - .gridDensity(16) - .passBandCutoff(3000) - .passBandAmplitude(1.0) - .passBandRipple(0.01) - .stopBandStart(4000) - .stopBandAmplitude(0.0) - .stopBandRipple(0.027) + //Band-pass filter to both decimate (48kHz to 8kHz) and block 0 - 300 Hz (LTR signalling). + FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder() + .sampleRate( 48000 ) + .stopFrequency1( 150 ) + .passFrequencyBegin( 300 ) + .passFrequencyEnd( 3500 ) + .stopFrequency2( 4000 ) + .stopRipple( 0.0004 ) + .passRipple( 0.008) .build(); RemezFIRFilterDesigner designer = new RemezFIRFilterDesigner(specification); @@ -86,16 +86,12 @@ public class AudioModule extends Module implements IAudioPacketProvider, private Listener mAudioPacketListener; private PolyphaseFIRDecimatingFilter_RB mAudioDecimationFilter; - //TODO: remove this -- is being replaced by the DemodulatedAudioFilterModule - private RealFIRFilter_R_R mAudioFilter = new RealFIRFilter_R_R( - Filters.FIR_BANDPASS_AUDIO_48KHZ.getCoefficients(), 2.0f); - public AudioModule(boolean record) { mSourceID = ++UNIQUE_ID; mAudioMetadata = new AudioMetadata(mSourceID, record); - mAudioDecimationFilter = new PolyphaseFIRDecimatingFilter_RB(mDecimationCoefficients, 6); + mAudioDecimationFilter = new PolyphaseFIRDecimatingFilter_RB(mDecimationCoefficients, 6, 2.0f); mAudioDecimationFilter.setListener(new Listener() { @Override diff --git a/src/dsp/filter/design/FilterViewer.java b/src/dsp/filter/design/FilterViewer.java index 8285cf84..3b84c4a4 100644 --- a/src/dsp/filter/design/FilterViewer.java +++ b/src/dsp/filter/design/FilterViewer.java @@ -40,37 +40,35 @@ public class FilterViewer extends Application */ private float[] getFilter() { - FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() - .sampleRate( 48000 ) - .gridDensity( 16 ) - .passBandCutoff( 3000 ) +// FIRFilterSpecification specification = FIRFilterSpecification.lowPassBuilder() +// .sampleRate( 48000 ) +// .gridDensity( 16 ) +// .passBandCutoff( 3000 ) +// .passBandAmplitude( 1.0 ) +// .passBandRipple( 0.01 ) +// .stopBandStart( 4000 ) +// .stopBandAmplitude( 0.0 ) +// .stopBandRipple( 0.027 ) +// .build(); + + FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder() + .sampleRate( 8000 ) + .stopBandCutoff( 250 ) + .stopBandAmplitude( 0.0 ) + .stopBandRipple( 0.01 ) + .passBandStart( 300 ) .passBandAmplitude( 1.0 ) .passBandRipple( 0.01 ) - .stopBandStart( 4000 ) - .stopBandAmplitude( 0.0 ) - .stopBandRipple( 0.027 ) .build(); - -// FIRFilterSpecification specification = FIRFilterSpecification.highPassBuilder() -// .sampleRate( 8000 ) -// .gridDensity( 16 ) -// .stopBandCutoff( 2000 ) -// .stopBandAmplitude( 0.0 ) -// .stopBandRipple( 0.003 ) -// .passBandStart( 3000 ) -// .passBandAmplitude( 1.0 ) -// .passBandRipple( 0.001 ) -// .build(); // FIRFilterSpecification specification = FIRFilterSpecification.bandPassBuilder() -// .sampleRate( 8000 ) -// .order( 164 ) -// .stopFrequency1( 1100 ) -// .passFrequencyBegin( 1200 ) -// .passFrequencyEnd( 2400 ) -// .stopFrequency2( 2500 ) -// .stopRipple( 0.01 ) -// .passRipple( 0.01 ) +// .sampleRate( 48000 ) +// .stopFrequency1( 150 ) +// .passFrequencyBegin( 200 ) +// .passFrequencyEnd( 3950 ) +// .stopFrequency2( 4000 ) +// .stopRipple( 0.0005 ) +// .passRipple( 0.003) // .build(); float[] taps = null; diff --git a/src/dsp/filter/polyphase/PolyphaseFIRDecimatingFilter_RB.java b/src/dsp/filter/polyphase/PolyphaseFIRDecimatingFilter_RB.java index 33212c0b..b312cad2 100644 --- a/src/dsp/filter/polyphase/PolyphaseFIRDecimatingFilter_RB.java +++ b/src/dsp/filter/polyphase/PolyphaseFIRDecimatingFilter_RB.java @@ -43,6 +43,7 @@ public class PolyphaseFIRDecimatingFilter_RB extends FIRFilter implements Listen private RealToRealBufferAssembler mAssembler; private int mDecimationRatio; private float mAccumulator = 0.0f; + private float mGain = 1.0f; /** * Polyphase filter stage for decimating real-valued sample buffers by the decimation ratio. Creates a number of @@ -55,10 +56,13 @@ public class PolyphaseFIRDecimatingFilter_RB extends FIRFilter implements Listen * to the nyquist frequency for an output sample rate equal to the input sample rate divided by the decimation ratio. * * @param decimationRatio to decimate the input sample rate by. + * @param gain to apply to the filtered output. Use a value of 1.0 to apply no gain. */ - public PolyphaseFIRDecimatingFilter_RB(float[] coefficients, int decimationRatio) + public PolyphaseFIRDecimatingFilter_RB(float[] coefficients, int decimationRatio, float gain) { mDecimationRatio = decimationRatio; + mGain = gain; + createFilterStages(coefficients, mDecimationRatio); mFilterStagePointer = mFilterStages.size() - 1; } @@ -127,7 +131,7 @@ public class PolyphaseFIRDecimatingFilter_RB extends FIRFilter implements Listen if(mFilterStagePointer < 0) { - mAssembler.receive(mAccumulator); + mAssembler.receive(mAccumulator * mGain); mAccumulator = 0.0f; mFilterStagePointer = mFilterStages.size() - 1; @@ -177,7 +181,7 @@ public class PolyphaseFIRDecimatingFilter_RB extends FIRFilter implements Listen } float[] coefficients = designer.getImpulseResponse(); - PolyphaseFIRDecimatingFilter_RB filter = new PolyphaseFIRDecimatingFilter_RB(coefficients, 6); + PolyphaseFIRDecimatingFilter_RB filter = new PolyphaseFIRDecimatingFilter_RB(coefficients, 6, 1.0f); filter.setListener(new Listener() { @Override diff --git a/src/module/decode/ltrnet/LTRNetDecoderState.java b/src/module/decode/ltrnet/LTRNetDecoderState.java index 6f17d77a..56b0df90 100644 --- a/src/module/decode/ltrnet/LTRNetDecoderState.java +++ b/src/module/decode/ltrnet/LTRNetDecoderState.java @@ -1,17 +1,17 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014,2015 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 ******************************************************************************/ @@ -43,747 +43,755 @@ import audio.metadata.MetadataType; public class LTRNetDecoderState extends DecoderState { - private final static Logger mLog = LoggerFactory.getLogger( LTRNetDecoderState.class ); + private final static Logger mLog = LoggerFactory.getLogger(LTRNetDecoderState.class); - private DecimalFormat mDecimalFormatter = new DecimalFormat( "0.00000" ); + private DecimalFormat mDecimalFormatter = new DecimalFormat("0.00000"); - private TreeSet mTalkgroups = new TreeSet(); - private TreeSet mTalkgroupsFirstHeard = new TreeSet(); - private TreeSet mESNs = new TreeSet(); - private TreeSet mUniqueIDs = new TreeSet(); - private TreeSet mNeighborIDs = new TreeSet(); - private TreeSet mSiteIDs = new TreeSet(); - private HashMap mReceiveFrequencies = - new HashMap(); - private HashMap mTransmitFrequencies = - new HashMap(); - private HashMap mActiveCalls = new HashMap(); + private TreeSet mTalkgroups = new TreeSet(); + private TreeSet mTalkgroupsFirstHeard = new TreeSet(); + private TreeSet mESNs = new TreeSet(); + private TreeSet mUniqueIDs = new TreeSet(); + private TreeSet mNeighborIDs = new TreeSet(); + private TreeSet mSiteIDs = new TreeSet(); + private HashMap mReceiveFrequencies = + new HashMap(); + private HashMap mTransmitFrequencies = + new HashMap(); + private HashMap mActiveCalls = new HashMap(); - private String mTalkgroup; - private Alias mTalkgroupAlias; - private String mDescription; - private int mChannelNumber; - private long mFrequency = 0; + private String mTalkgroup; + private Alias mTalkgroupAlias; + private String mDescription; + private int mChannelNumber; + private long mFrequency = 0; - public LTRNetDecoderState( AliasList aliasList ) - { - super( aliasList ); - } - - @Override - public DecoderType getDecoderType() - { - return DecoderType.LTR_NET; - } - - @Override - public void receive( Message message ) + public LTRNetDecoderState(AliasList aliasList) { - if( message.isValid() ) - { - State state = State.IDLE; + super(aliasList); + } - if( message instanceof LTRNetOSWMessage ) - { - LTRNetOSWMessage ltr = (LTRNetOSWMessage)message; - - switch( ltr.getMessageType() ) - { - case CA_ENDD: - if( mChannelNumber == 0 ) - { - mChannelNumber = ltr.getChannel(); - broadcast( ChangedAttribute.CHANNEL_NUMBER ); - } + @Override + public DecoderType getDecoderType() + { + return DecoderType.LTR_NET; + } + + @Override + public void receive(Message message) + { + if (message.isValid()) + { + State state = State.IDLE; + + if (message instanceof LTRNetOSWMessage) + { + LTRNetOSWMessage ltr = (LTRNetOSWMessage) message; + + switch (ltr.getMessageType()) + { + case CA_ENDD: + if (mChannelNumber == 0) + { + mChannelNumber = ltr.getChannel(); + broadcast(ChangedAttribute.CHANNEL_NUMBER); + } /* Process FCC Station ID Events */ - if( ltr.getGroup() == 254 ) - { - if( mCurrentCallEvent == null || - mCurrentCallEvent.getCallEventType() != - CallEventType.STATION_ID ) - { - mCurrentCallEvent = new LTRCallEvent.Builder( - DecoderType.LTR_NET, CallEventType.STATION_ID ) - .aliasList( getAliasList() ) - .channel( String.valueOf( mChannelNumber ) ) - .frequency( mFrequency ) - .to( ltr.getTalkgroupID() ) - .build(); + if (ltr.getGroup() == 254) + { + if (mCurrentCallEvent == null || + mCurrentCallEvent.getCallEventType() != + CallEventType.STATION_ID) + { + mCurrentCallEvent = new LTRCallEvent.Builder( + DecoderType.LTR_NET, CallEventType.STATION_ID) + .aliasList(getAliasList()) + .channel(String.valueOf(mChannelNumber)) + .frequency(mFrequency) + .to(ltr.getTalkgroupID()) + .build(); - broadcast( mCurrentCallEvent ); - - broadcast( new DecoderStateEvent( this, - Event.START, State.DATA ) ); - } - else - { - broadcast( new DecoderStateEvent( this, - Event.CONTINUATION, State.DATA ) ); - } - } - else - { - processCallEndMessage( ltr ); - } - break; - case CA_STRT: - if( mChannelNumber == 0 ) - { - mChannelNumber = ltr.getChannel(); - broadcast( ChangedAttribute.CHANNEL_NUMBER ); - } + broadcast(mCurrentCallEvent); + + broadcast(new DecoderStateEvent(this, + Event.START, State.DATA)); + } + else + { + broadcast(new DecoderStateEvent(this, + Event.CONTINUATION, State.DATA)); + } + } + else + { + processCallEndMessage(ltr); + } + break; + case CA_STRT: + if (mChannelNumber == 0) + { + mChannelNumber = ltr.getChannel(); + broadcast(ChangedAttribute.CHANNEL_NUMBER); + } /* If the call event channel matches our current channel - * then it's a call, otherwise it's a call detect. */ - if( ltr.getChannel() == mChannelNumber ) - { - processCallMessage( ltr ); - } - else - { - processCallDetectMessage( ltr ); - } - - break; - case SY_IDLE: - if( mChannelNumber != ltr.getChannel() ) - { - mChannelNumber = ltr.getChannel(); - broadcast( ChangedAttribute.CHANNEL_NUMBER ); - } - break; - case MA_CHNH: - break; - case MA_CHNL: - break; - case FQ_RXHI: - case FQ_RXLO: - if( ltr.getFrequency() > 0 ) - { - mReceiveFrequencies.put( ltr.getHomeRepeater(), - ltr.getFrequency() ); - } - break; - case FQ_TXHI: - case FQ_TXLO: - if( ltr.getFrequency() > 0 ) - { - mTransmitFrequencies.put( ltr.getHomeRepeater(), - ltr.getFrequency() ); - } - break; - case ID_NBOR: - String neighborID = ltr.getNeighborID(); - - if( neighborID != null ) - { - mNeighborIDs.add( neighborID ); - } - break; - case ID_UNIQ: - state = State.DATA; - - int uniqueID = ltr.getRadioUniqueID(); - - if( uniqueID != LTRNetOSWMessage.INT_NULL_VALUE ) - { - mUniqueIDs.add( uniqueID ); - } - - if( getCurrentLTRCallEvent() == null ) - { - mCurrentCallEvent = new LTRCallEvent.Builder( - DecoderType.LTR_NET, CallEventType.REGISTER ) - .aliasList( getAliasList() ) - .channel( String.valueOf( mChannelNumber ) ) - .frequency( mFrequency ) - .from( String.valueOf( uniqueID ) ) - .build(); - } - else - { - mCurrentCallEvent.setFromID( - String.valueOf( ltr.getRadioUniqueID() ) ); - mCurrentCallEvent.setDetails( "Unique ID" ); - - broadcast( mCurrentCallEvent ); - } + * then it's a call, otherwise it's a call detect. */ + if (ltr.getChannel() == mChannelNumber) + { + processCallMessage(ltr); + } + else + { + processCallDetectMessage(ltr); + } - mTalkgroup = String.valueOf( uniqueID ); - broadcast( ChangedAttribute.TO_TALKGROUP ); - - mTalkgroupAlias = ltr.getRadioUniqueIDAlias(); - broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS ); - break; - case ID_SITE: - String siteID = ltr.getSiteID(); - - if( siteID != null ) - { - mSiteIDs.add( siteID ); - } - break; - default: - break; - } - } - else if( message instanceof LTRNetISWMessage ) - { - LTRNetISWMessage ltr = ((LTRNetISWMessage)message); - - switch( ltr.getMessageType() ) - { - case CA_STRT: - processCallMessage( ltr ); - break; - case CA_ENDD: - processCallEndMessage( ltr ); - break; - case ID_ESNH: - case ID_ESNL: - state = State.DATA; - - String esn = ltr.getESN(); - - if( !esn.contains( "xxxx" ) ) - { - mESNs.add( ltr.getESN() ); - } - - mDescription = "ESN"; - broadcast( ChangedAttribute.DESCRIPTION ); - - mTalkgroup = ltr.getESN(); - broadcast( ChangedAttribute.TO_TALKGROUP ); + break; + case SY_IDLE: + if (mChannelNumber != ltr.getChannel()) + { + mChannelNumber = ltr.getChannel(); + broadcast(ChangedAttribute.CHANNEL_NUMBER); + } + break; + case MA_CHNH: + break; + case MA_CHNL: + break; + case FQ_RXHI: + case FQ_RXLO: + if (ltr.getFrequency() > 0) + { + mReceiveFrequencies.put(ltr.getHomeRepeater(), + ltr.getFrequency()); + } + break; + case FQ_TXHI: + case FQ_TXLO: + if (ltr.getFrequency() > 0) + { + mTransmitFrequencies.put(ltr.getHomeRepeater(), + ltr.getFrequency()); + } + break; + case ID_NBOR: + String neighborID = ltr.getNeighborID(); - mTalkgroupAlias = ltr.getESNAlias(); - broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS ); + if (neighborID != null) + { + mNeighborIDs.add(neighborID); + } + break; + case ID_UNIQ: + state = State.DATA; - broadcast( new DecoderStateEvent( this, Event.DECODE, State.DATA ) ); + int uniqueID = ltr.getRadioUniqueID(); - if( mCurrentCallEvent == null ) - { - mCurrentCallEvent = new LTRCallEvent.Builder( - DecoderType.LTR_NET, CallEventType.REGISTER_ESN ) - .aliasList( getAliasList() ) - .details( "ESN:" + ltr.getESN() ) - .frequency( mFrequency ) - .from( ltr.getESN() ) - .build(); - - broadcast( mCurrentCallEvent ); - } - - break; - case ID_UNIQ: - state = State.DATA; - - int uniqueid = ltr.getRadioUniqueID(); - - if( uniqueid != LTRNetISWMessage.INT_NULL_VALUE ) - { - mUniqueIDs.add( uniqueid ); - - mDescription = "REGISTER UID"; - broadcast( ChangedAttribute.DESCRIPTION ); + if (uniqueID != LTRNetOSWMessage.INT_NULL_VALUE) + { + mUniqueIDs.add(uniqueID); + } - mTalkgroup = String.valueOf( uniqueid ); - broadcast( ChangedAttribute.TO_TALKGROUP ); + if (getCurrentLTRCallEvent() == null) + { + mCurrentCallEvent = new LTRCallEvent.Builder( + DecoderType.LTR_NET, CallEventType.REGISTER) + .aliasList(getAliasList()) + .channel(String.valueOf(mChannelNumber)) + .frequency(mFrequency) + .from(String.valueOf(uniqueID)) + .build(); + } + else + { + mCurrentCallEvent.setFromID( + String.valueOf(ltr.getRadioUniqueID())); + mCurrentCallEvent.setDetails("Unique ID"); - mTalkgroupAlias = ltr.getRadioUniqueIDAlias(); - broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS ); - - if( getCurrentLTRCallEvent() == null ) - { - mCurrentCallEvent = new LTRCallEvent.Builder( - DecoderType.LTR_NET, CallEventType.REGISTER ) - .aliasList( getAliasList() ) - .channel( String.valueOf( mChannelNumber ) ) - .frequency( mFrequency ) - .from( String.valueOf( uniqueid ) ) - .build(); - } - else - { - mCurrentCallEvent.setFromID( - String.valueOf( ltr.getRadioUniqueID() ) ); - mCurrentCallEvent.setDetails( "Unique ID" ); - - broadcast( mCurrentCallEvent ); - } - } - break; - default: - break; - } - } - } + broadcast(mCurrentCallEvent); + } + + mTalkgroup = String.valueOf(uniqueID); + broadcast(ChangedAttribute.TO_TALKGROUP); + + mTalkgroupAlias = ltr.getRadioUniqueIDAlias(); + broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS); + break; + case ID_SITE: + String siteID = ltr.getSiteID(); + + if (siteID != null) + { + mSiteIDs.add(siteID); + } + break; + default: + break; + } + } + else if (message instanceof LTRNetISWMessage) + { + LTRNetISWMessage ltr = ((LTRNetISWMessage) message); + + switch (ltr.getMessageType()) + { + case CA_STRT: + processCallMessage(ltr); + break; + case CA_ENDD: + processCallEndMessage(ltr); + break; + case ID_ESNH: + case ID_ESNL: + state = State.DATA; + + String esn = ltr.getESN(); + + if (!esn.contains("xxxx")) + { + mESNs.add(ltr.getESN()); + } + + mDescription = "ESN"; + broadcast(ChangedAttribute.DESCRIPTION); + + mTalkgroup = ltr.getESN(); + broadcast(ChangedAttribute.TO_TALKGROUP); + + mTalkgroupAlias = ltr.getESNAlias(); + broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS); + + broadcast(new DecoderStateEvent(this, Event.DECODE, State.DATA)); + + if (mCurrentCallEvent == null) + { + mCurrentCallEvent = new LTRCallEvent.Builder( + DecoderType.LTR_NET, CallEventType.REGISTER_ESN) + .aliasList(getAliasList()) + .details("ESN:" + ltr.getESN()) + .frequency(mFrequency) + .from(ltr.getESN()) + .build(); + + broadcast(mCurrentCallEvent); + } + + break; + case ID_UNIQ: + state = State.DATA; + + int uniqueid = ltr.getRadioUniqueID(); + + if (uniqueid != LTRNetISWMessage.INT_NULL_VALUE) + { + mUniqueIDs.add(uniqueid); + + mDescription = "REGISTER UID"; + broadcast(ChangedAttribute.DESCRIPTION); + + mTalkgroup = String.valueOf(uniqueid); + broadcast(ChangedAttribute.TO_TALKGROUP); + + mTalkgroupAlias = ltr.getRadioUniqueIDAlias(); + broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS); + + if (getCurrentLTRCallEvent() == null) + { + mCurrentCallEvent = new LTRCallEvent.Builder( + DecoderType.LTR_NET, CallEventType.REGISTER) + .aliasList(getAliasList()) + .channel(String.valueOf(mChannelNumber)) + .frequency(mFrequency) + .from(String.valueOf(uniqueid)) + .build(); + } + else + { + mCurrentCallEvent.setFromID( + String.valueOf(ltr.getRadioUniqueID())); + mCurrentCallEvent.setDetails("Unique ID"); + + broadcast(mCurrentCallEvent); + } + } + break; + default: + break; + } + } + } } - - public LTRCallEvent getCurrentLTRCallEvent() - { - if( mCurrentCallEvent != null ) - { - return (LTRCallEvent)mCurrentCallEvent; - } - - return null; - } - - @Override + + public LTRCallEvent getCurrentLTRCallEvent() + { + if (mCurrentCallEvent != null) + { + return (LTRCallEvent) mCurrentCallEvent; + } + + return null; + } + + @Override public String getActivitySummary() { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); - sb.append( "Activity Summary\n" ); - sb.append( "Decoder:\tLTR-Net\n\n" ); + sb.append("Activity Summary\n"); + sb.append("Decoder:\tLTR-Net\n\n"); - if( mSiteIDs.isEmpty() ) - { - sb.append( "Site:\tUnknown\n" ); - } - else - { - Iterator it = mSiteIDs.iterator(); - - while( it.hasNext() ) - { - sb.append( "Site:\t" ); - - String siteID = it.next(); + if (mSiteIDs.isEmpty()) + { + sb.append("Site:\tUnknown\n"); + } + else + { + Iterator it = mSiteIDs.iterator(); - sb.append( siteID ); - - if( hasAliasList() ) - { - Alias siteAlias = getAliasList().getSiteID( String.valueOf( siteID ) ); + while (it.hasNext()) + { + sb.append("Site:\t"); - if( siteAlias != null ) - { - sb.append( " " ); - sb.append( siteAlias.getName() ); - } - } + String siteID = it.next(); - sb.append( "\n" ); - } - } - - sb.append( "\nLCNs (transmit | receive)\n" ); - - if( mReceiveFrequencies.isEmpty() && mTransmitFrequencies.isEmpty() ) - { - sb.append( " None\n" ); - } - else - { - for( int x = 1; x < 21; x++ ) - { - long rcv = 0; - - if( mReceiveFrequencies.containsKey( x ) ) - { - rcv = mReceiveFrequencies.get( x ); - } - - long xmt = 0; - - if( mTransmitFrequencies.containsKey( x ) ) - { - xmt = mTransmitFrequencies.get( x ); - } + sb.append(siteID); - if( rcv > 0 || xmt > 0 ) - { - if( x < 10 ) - { - sb.append( " " ); - } + if (hasAliasList()) + { + Alias siteAlias = getAliasList().getSiteID(String.valueOf(siteID)); - sb.append( x ); - sb.append( ": " ); + if (siteAlias != null) + { + sb.append(" "); + sb.append(siteAlias.getName()); + } + } - if( xmt == 0 ) - { - sb.append( "---.-----" ); - } - else - { - sb.append( mDecimalFormatter.format( (double)xmt/1E6d ) ); - } - sb.append( " | " ); - - if( rcv == 0 ) - { - sb.append( "---.-----" ); - } - else - { - sb.append( mDecimalFormatter.format( (double)rcv/1E6d ) ); - } - - if( x == mChannelNumber ) - { - sb.append( " **" ); - } - - sb.append( "\n" ); - } - } - } - - sb.append( "\nTalkgroups\n" ); - - if( mTalkgroups.isEmpty() ) - { - sb.append( " None\n" ); - } - else - { - Iterator it = mTalkgroups.iterator(); - - while( it.hasNext() ) - { - String tgid = it.next(); - - sb.append( " " ); - sb.append( tgid ); - sb.append( " " ); - - if( hasAliasList() ) - { - Alias alias = getAliasList().getTalkgroupAlias( tgid ); - - if( alias != null ) - { - sb.append( alias.getName() ); - } - } - - sb.append( "\n" ); - } - } - - sb.append( "\nRadio Unique IDs\n" ); - - if( mUniqueIDs.isEmpty() ) - { - sb.append( " None\n" ); - } - else - { - Iterator it = mUniqueIDs.iterator(); - - while( it.hasNext() ) - { - int uid = it.next(); - - sb.append( " " ); - sb.append( uid ); - sb.append( " " ); - - if( hasAliasList() ) - { - Alias alias = getAliasList().getUniqueID( uid ); - - if( alias != null ) - { - sb.append( alias.getName() ); - } - } - - sb.append( "\n" ); - } - } + sb.append("\n"); + } + } - sb.append( "\nESNs\n" ); - - if( mESNs.isEmpty() ) - { - sb.append( " None\n" ); - } - else - { - Iterator it = mESNs.iterator(); - - while( it.hasNext() ) - { - String esn = it.next(); - - sb.append( " " ); - sb.append( esn ); - sb.append( " " ); - - if( hasAliasList() ) - { - Alias alias = getAliasList().getESNAlias( esn ); - - if( alias != null ) - { - sb.append( alias.getName() ); - } - } - - sb.append( "\n" ); - } - } - - sb.append( "\nNeighbor Sites\n" ); - - if( mNeighborIDs.isEmpty() ) - { - sb.append( " None\n" ); - } - else - { - Iterator it = mNeighborIDs.iterator(); - - while( it.hasNext() ) - { - String neighbor = it.next(); - - sb.append( " " ); - sb.append( neighbor ); - sb.append( " " ); - - if( hasAliasList() ) - { - Alias alias = getAliasList().getSiteID( String.valueOf( neighbor ) ); - - if( alias != null ) - { - sb.append( alias.getName() ); - } - } - - sb.append( "\n" ); - } - } - - return sb.toString(); + sb.append("\nLCNs (transmit | receive)\n"); + + if (mReceiveFrequencies.isEmpty() && mTransmitFrequencies.isEmpty()) + { + sb.append(" None\n"); + } + else + { + for (int x = 1; x < 21; x++) + { + long rcv = 0; + + if (mReceiveFrequencies.containsKey(x)) + { + rcv = mReceiveFrequencies.get(x); + } + + long xmt = 0; + + if (mTransmitFrequencies.containsKey(x)) + { + xmt = mTransmitFrequencies.get(x); + } + + if (rcv > 0 || xmt > 0) + { + if (x < 10) + { + sb.append(" "); + } + + sb.append(x); + sb.append(": "); + + if (xmt == 0) + { + sb.append("---.-----"); + } + else + { + sb.append(mDecimalFormatter.format((double) xmt / 1E6d)); + } + sb.append(" | "); + + if (rcv == 0) + { + sb.append("---.-----"); + } + else + { + sb.append(mDecimalFormatter.format((double) rcv / 1E6d)); + } + + if (x == mChannelNumber) + { + sb.append(" **"); + } + + sb.append("\n"); + } + } + } + + sb.append("\nTalkgroups\n"); + + if (mTalkgroups.isEmpty()) + { + sb.append(" None\n"); + } + else + { + Iterator it = mTalkgroups.iterator(); + + while (it.hasNext()) + { + String tgid = it.next(); + + sb.append(" "); + sb.append(tgid); + sb.append(" "); + + if (hasAliasList()) + { + Alias alias = getAliasList().getTalkgroupAlias(tgid); + + if (alias != null) + { + sb.append(alias.getName()); + } + } + + sb.append("\n"); + } + } + + sb.append("\nRadio Unique IDs\n"); + + if (mUniqueIDs.isEmpty()) + { + sb.append(" None\n"); + } + else + { + Iterator it = mUniqueIDs.iterator(); + + while (it.hasNext()) + { + int uid = it.next(); + + sb.append(" "); + sb.append(uid); + sb.append(" "); + + if (hasAliasList()) + { + Alias alias = getAliasList().getUniqueID(uid); + + if (alias != null) + { + sb.append(alias.getName()); + } + } + + sb.append("\n"); + } + } + + sb.append("\nESNs\n"); + + if (mESNs.isEmpty()) + { + sb.append(" None\n"); + } + else + { + Iterator it = mESNs.iterator(); + + while (it.hasNext()) + { + String esn = it.next(); + + sb.append(" "); + sb.append(esn); + sb.append(" "); + + if (hasAliasList()) + { + Alias alias = getAliasList().getESNAlias(esn); + + if (alias != null) + { + sb.append(alias.getName()); + } + } + + sb.append("\n"); + } + } + + sb.append("\nNeighbor Sites\n"); + + if (mNeighborIDs.isEmpty()) + { + sb.append(" None\n"); + } + else + { + Iterator it = mNeighborIDs.iterator(); + + while (it.hasNext()) + { + String neighbor = it.next(); + + sb.append(" "); + sb.append(neighbor); + sb.append(" "); + + if (hasAliasList()) + { + Alias alias = getAliasList().getSiteID(String.valueOf(neighbor)); + + if (alias != null) + { + sb.append(alias.getName()); + } + } + + sb.append("\n"); + } + } + + return sb.toString(); } - /** - * Call Detect - current channel messages indicate a call on another channel - */ - private void processCallDetectMessage( LTRNetMessage message ) - { - if( !mActiveCalls.containsKey( message.getChannel() ) || - !mActiveCalls.get( message.getChannel() ).contentEquals( message.getTalkgroupID() ) ) - { - mActiveCalls.put( message.getChannel(), message.getTalkgroupID() ); - - int channel = message.getChannel(); + /** + * Call Detect - current channel messages indicate a call on another channel + */ + private void processCallDetectMessage(LTRNetMessage message) + { + if (!mActiveCalls.containsKey(message.getChannel()) || + !mActiveCalls.get(message.getChannel()).contentEquals(message.getTalkgroupID())) + { + mActiveCalls.put(message.getChannel(), message.getTalkgroupID()); - long frequency = 0; - - if( mTransmitFrequencies.containsKey( channel ) ) - { - frequency = mTransmitFrequencies.get( channel ); - } + int channel = message.getChannel(); - broadcast( new LTRCallEvent.Builder( DecoderType.LTR_NET, CallEventType.CALL_DETECT ) - .aliasList( getAliasList() ) - .channel( String.valueOf( message.getChannel() ) ) - .frequency( frequency ) - .to( message.getTalkgroupID() ) - .build() ); - } - - broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.IDLE ) ); - } - - /** - * Indicates if the talkgroup is different than the talkgroup specified in - * the current call event - */ - private boolean isDifferentTalkgroup( String talkgroup ) - { - return talkgroup != null && - mCurrentCallEvent != null && - mCurrentCallEvent.getToID() != null && - !mCurrentCallEvent.getToID().contentEquals( talkgroup ); - } - - private void processCallMessage( LTRNetMessage message ) - { - int group = message.getGroup(); + long frequency = 0; + + if (mTransmitFrequencies.containsKey(channel)) + { + frequency = mTransmitFrequencies.get(channel); + } + + broadcast(new LTRCallEvent.Builder(DecoderType.LTR_NET, CallEventType.CALL_DETECT) + .aliasList(getAliasList()) + .channel(String.valueOf(message.getChannel())) + .frequency(frequency) + .to(message.getTalkgroupID()) + .build()); + } + + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.IDLE)); + } + + /** + * Indicates if the talkgroup is different than the talkgroup specified in + * the current call event + */ + private boolean isDifferentTalkgroup(String talkgroup) + { + return talkgroup != null && + mCurrentCallEvent != null && + mCurrentCallEvent.getToID() != null && + !mCurrentCallEvent.getToID().contentEquals(talkgroup); + } + + private boolean isValidTalkgroup(String talkgroup) + { + return talkgroup != null && !talkgroup.matches("0-00-000"); + } + + private void processCallMessage(LTRNetMessage message) + { + int group = message.getGroup(); /* Process call registration */ - if( group == 253 ) - { - broadcast( new DecoderStateEvent( this, Event.START, State.DATA ) ); - mDescription = "REGISTER"; - broadcast( ChangedAttribute.DESCRIPTION ); - } - /* Process call */ - else - { - String talkgroup = message.getTalkgroupID(); + if (group == 253) + { + broadcast(new DecoderStateEvent(this, Event.START, State.DATA)); + mDescription = "REGISTER"; + broadcast(ChangedAttribute.DESCRIPTION); + } + /* Process call */ + else + { + String talkgroup = message.getTalkgroupID(); + + if (isValidTalkgroup(talkgroup)) + { + final LTRCallEvent current = getCurrentLTRCallEvent(); - final LTRCallEvent current = getCurrentLTRCallEvent(); - /* If this is a new call or the talkgroup is different from the current * call, create a new call event */ - if( current == null || isDifferentTalkgroup( talkgroup ) ) - { + if (current == null || isDifferentTalkgroup(talkgroup)) + { /* Invalidate the current call */ - if( current != null ) - { - current.setValid( false ); - broadcast( current ); - } - - mTalkgroup = message.getTalkgroupID(); - broadcast( ChangedAttribute.TO_TALKGROUP ); + if (current != null) + { + current.setValid(false); + broadcast(current); + } + + mTalkgroup = message.getTalkgroupID(); + broadcast(ChangedAttribute.TO_TALKGROUP); /* A talkgroup must be seen at least once before it will be added * to the mTalkgroups list that is used in the activity summary, * so that we don't pollute the summary with one-off error talkgroups */ - if( mTalkgroupsFirstHeard.contains( mTalkgroup ) ) - { - mTalkgroups.add( mTalkgroup ); - } - else - { - mTalkgroupsFirstHeard.add( mTalkgroup ); - } - - mTalkgroupAlias = message.getTalkgroupIDAlias(); - broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS ); + if (mTalkgroupsFirstHeard.contains(mTalkgroup)) + { + mTalkgroups.add(mTalkgroup); + } + else + { + mTalkgroupsFirstHeard.add(mTalkgroup); + } - CallEvent callEvent = new LTRCallEvent.Builder( DecoderType.LTR_NET, CallEventType.CALL ) - .aliasList( getAliasList() ) - .channel( String.valueOf( message.getChannel() ) ) - .frequency( mFrequency ) - .to( message.getTalkgroupID() ) - .build(); - - broadcast( callEvent ); - - mCurrentCallEvent = callEvent; - - broadcast( new Metadata( MetadataType.TO, mTalkgroup, mTalkgroupAlias, true ) ); + mTalkgroupAlias = message.getTalkgroupIDAlias(); + broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS); - broadcast( new DecoderStateEvent( this, Event.START, State.CALL ) ); - } + CallEvent callEvent = new LTRCallEvent.Builder(DecoderType.LTR_NET, CallEventType.CALL) + .aliasList(getAliasList()) + .channel(String.valueOf(message.getChannel())) + .frequency(mFrequency) + .to(message.getTalkgroupID()) + .build(); - broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CALL ) ); - } - } - - private void processCallEndMessage( LTRNetMessage message ) - { - if( mCurrentCallEvent != null && - mCurrentCallEvent.getCallEventType() == CallEventType.CALL ) - { - mCurrentCallEvent.setEnd( System.currentTimeMillis() ); - broadcast( mCurrentCallEvent ); - } + broadcast(callEvent); - mCurrentCallEvent = null; - - broadcast( new DecoderStateEvent( this, Event.END, State.FADE ) ); - } + mCurrentCallEvent = callEvent; - /** - * Performs a full reset - */ - public void reset() - { - mChannelNumber = 0; - - mActiveCalls.clear(); - mESNs.clear(); - mNeighborIDs.clear(); - mReceiveFrequencies.clear(); - mSiteIDs.clear(); - mTalkgroups.clear(); - mTransmitFrequencies.clear(); - mUniqueIDs.clear(); - - resetState(); - } + broadcast(new Metadata(MetadataType.TO, mTalkgroup, mTalkgroupAlias, true)); - /** - * Resets the decoder state after a call or other decode event - */ - private void resetState() - { - if( mCurrentCallEvent != null && mCurrentCallEvent - .getCallEventType() == CallEventType.CALL ) - { - mCurrentCallEvent.end(); - broadcast( mCurrentCallEvent ); - } - - mCurrentCallEvent = null; - - mTalkgroup = null; - broadcast( ChangedAttribute.TO_TALKGROUP ); + broadcast(new DecoderStateEvent(this, Event.START, State.CALL)); + } - mTalkgroupAlias = null; - broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS ); + broadcast(new DecoderStateEvent(this, Event.CONTINUATION, State.CALL)); + } + } + } - mDescription = null; - broadcast( ChangedAttribute.DESCRIPTION ); - } + private void processCallEndMessage(LTRNetMessage message) + { + if (mCurrentCallEvent != null && + mCurrentCallEvent.getCallEventType() == CallEventType.CALL) + { + mCurrentCallEvent.setEnd(System.currentTimeMillis()); + broadcast(mCurrentCallEvent); + } - public String getToTalkgroup() - { - return mTalkgroup; - } - - public Alias getToTalkgroupAlias() - { - return mTalkgroupAlias; - } - - public String getDescription() - { - return mDescription; - } - - public boolean hasChannelNumber() - { - return mChannelNumber != 0; - } - - public int getChannelNumber() - { - return mChannelNumber; - } + mCurrentCallEvent = null; - @Override - public void init() - { + broadcast(new DecoderStateEvent(this, Event.END, State.FADE)); + } + + /** + * Performs a full reset + */ + public void reset() + { + mChannelNumber = 0; + + mActiveCalls.clear(); + mESNs.clear(); + mNeighborIDs.clear(); + mReceiveFrequencies.clear(); + mSiteIDs.clear(); + mTalkgroups.clear(); + mTransmitFrequencies.clear(); + mUniqueIDs.clear(); + + resetState(); + } + + /** + * Resets the decoder state after a call or other decode event + */ + private void resetState() + { + if (mCurrentCallEvent != null && mCurrentCallEvent + .getCallEventType() == CallEventType.CALL) + { + mCurrentCallEvent.end(); + broadcast(mCurrentCallEvent); + } + + mCurrentCallEvent = null; + + mTalkgroup = null; + broadcast(ChangedAttribute.TO_TALKGROUP); + + mTalkgroupAlias = null; + broadcast(ChangedAttribute.TO_TALKGROUP_ALIAS); + + mDescription = null; + broadcast(ChangedAttribute.DESCRIPTION); + } + + public String getToTalkgroup() + { + return mTalkgroup; + } + + public Alias getToTalkgroupAlias() + { + return mTalkgroupAlias; + } + + public String getDescription() + { + return mDescription; + } + + public boolean hasChannelNumber() + { + return mChannelNumber != 0; + } + + public int getChannelNumber() + { + return mChannelNumber; + } + + @Override + public void init() + { /* No initialization steps required */ - } - - @Override - public void receiveDecoderStateEvent( DecoderStateEvent event ) - { - switch( event.getEvent() ) - { - case RESET: - resetState(); - break; - case SOURCE_FREQUENCY: - mFrequency = event.getFrequency(); - break; - default: - break; - } - } + } - @Override - public void start( ScheduledExecutorService executor ) - { - } + @Override + public void receiveDecoderStateEvent(DecoderStateEvent event) + { + switch (event.getEvent()) + { + case RESET: + resetState(); + break; + case SOURCE_FREQUENCY: + mFrequency = event.getFrequency(); + break; + default: + break; + } + } - @Override - public void stop() - { - } + @Override + public void start(ScheduledExecutorService executor) + { + } + + @Override + public void stop() + { + } } diff --git a/src/module/decode/p25/audio/P25AudioModule.java b/src/module/decode/p25/audio/P25AudioModule.java index 4d062945..fbc28f00 100644 --- a/src/module/decode/p25/audio/P25AudioModule.java +++ b/src/module/decode/p25/audio/P25AudioModule.java @@ -152,8 +152,12 @@ public class P25AudioModule extends Module implements Listener, if (!mLibraryLoadStatusLogged) { - mLog.info("JMBE audio conversion library successfully loaded" - + " - P25 audio will be available"); + StringBuilder sb = new StringBuilder(); + sb.append("JMBE audio conversion library ["); + sb.append(library.getVersion()); + sb.append("] successfully loaded - P25 audio will be available"); + + mLog.info(sb.toString()); mLibraryLoadStatusLogged = true; }