diff --git a/src/main/java/io/github/dsheirer/audio/AbstractAudioModule.java b/src/main/java/io/github/dsheirer/audio/AbstractAudioModule.java index 99e1f1c3..376f76c7 100644 --- a/src/main/java/io/github/dsheirer/audio/AbstractAudioModule.java +++ b/src/main/java/io/github/dsheirer/audio/AbstractAudioModule.java @@ -49,11 +49,14 @@ public abstract class AbstractAudioModule extends Module implements IAudioSegmen /** * Constructs an abstract audio module + * + * @param aliasList for aliasing identifiers + * @param maxSegmentAudioSampleLength in milliseconds */ - public AbstractAudioModule(AliasList aliasList, int maxSegmentAudioSampleLength) + public AbstractAudioModule(AliasList aliasList, long maxSegmentAudioSampleLength) { mAliasList = aliasList; - mMaxSegmentAudioSampleLength = maxSegmentAudioSampleLength; + mMaxSegmentAudioSampleLength = (int)(maxSegmentAudioSampleLength * 8); //Convert milliseconds to samples mIdentifierUpdateNotificationBroadcaster.addListener(mIdentifierCollection); } diff --git a/src/main/java/io/github/dsheirer/audio/AudioModule.java b/src/main/java/io/github/dsheirer/audio/AudioModule.java index f71ded9a..93bc363e 100644 --- a/src/main/java/io/github/dsheirer/audio/AudioModule.java +++ b/src/main/java/io/github/dsheirer/audio/AudioModule.java @@ -79,10 +79,13 @@ public class AudioModule extends AbstractAudioModule implements ISquelchStateLis /** * Creates an Audio Module. + * + * @param aliasList for aliasing identifiers + * @param maxAudioSegmentLength in milliseconds */ - public AudioModule(AliasList aliasList, int maxSegmentAudioSampleLength) + public AudioModule(AliasList aliasList, long maxAudioSegmentLength) { - super(aliasList, maxSegmentAudioSampleLength); + super(aliasList, maxAudioSegmentLength); } /** @@ -124,17 +127,17 @@ public class AudioModule extends AbstractAudioModule implements ISquelchStateLis } @Override - public void receive(ReusableFloatBuffer reusableFloatBuffer) + public void receive(ReusableFloatBuffer audioBuffer) { if(mSquelchState == SquelchState.UNSQUELCH) { - ReusableFloatBuffer buffer = mHighPassFilter.filter(reusableFloatBuffer); - addAudio(buffer.getSamples()); - buffer.decrementUserCount(); + ReusableFloatBuffer highPassFilteredAudio = mHighPassFilter.filter(audioBuffer); + addAudio(highPassFilteredAudio.getSamplesCopy()); + highPassFilteredAudio.decrementUserCount(); } else { - reusableFloatBuffer.decrementUserCount(); + audioBuffer.decrementUserCount(); } } diff --git a/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java b/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java index 6e5bb308..f885b73b 100644 --- a/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java +++ b/src/main/java/io/github/dsheirer/channel/state/ChangeChannelTimeoutEvent.java @@ -30,15 +30,28 @@ import io.github.dsheirer.controller.channel.Channel.ChannelType; public class ChangeChannelTimeoutEvent extends DecoderStateEvent { private ChannelType mChannelType; - private long mCallTimeout; + private long mCallTimeoutMilliseconds; + /** + * Constructs an instance + * @param source of the event + * @param channelType for the event + * @param timeout in milliseconds + * @param timeslot of the event + */ public ChangeChannelTimeoutEvent(Object source, ChannelType channelType, long timeout, int timeslot) { super(source, Event.CHANGE_CALL_TIMEOUT, State.IDLE, timeslot); mChannelType = channelType; - mCallTimeout = timeout; + mCallTimeoutMilliseconds = timeout; } + /** + * Constructs an instance + * @param source of the event + * @param channelType for the event + * @param timeout value in milliseconds + */ public ChangeChannelTimeoutEvent(Object source, ChannelType channelType, long timeout) { this(source, channelType, timeout, 0); @@ -49,8 +62,11 @@ public class ChangeChannelTimeoutEvent extends DecoderStateEvent return mChannelType; } - public long getCallTimeout() + /** + * Call timeout value in milliseconds + */ + public long getCallTimeoutMilliseconds() { - return mCallTimeout; + return mCallTimeoutMilliseconds; } } \ No newline at end of file diff --git a/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java b/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java index 4940b562..1377dede 100644 --- a/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java +++ b/src/main/java/io/github/dsheirer/channel/state/MultiChannelState.java @@ -115,14 +115,14 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS stateMachine.setChannelType(mChannel.getChannelType()); stateMachine.setIdentifierUpdateListener(mutableIdentifierCollection); - stateMachine.setEndTimeoutBuffer(RESET_TIMEOUT_DELAY); + stateMachine.setEndTimeoutBufferMilliseconds(RESET_TIMEOUT_DELAY); if(channel.getChannelType() == ChannelType.STANDARD) { - stateMachine.setFadeTimeoutBuffer(FADE_TIMEOUT_DELAY); + stateMachine.setFadeTimeoutBufferMilliseconds(FADE_TIMEOUT_DELAY); } else { - stateMachine.setFadeTimeoutBuffer(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000); + stateMachine.setFadeTimeoutBufferMilliseconds(DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS * 1000); } } @@ -529,7 +529,7 @@ public class MultiChannelState extends AbstractChannelState implements IDecoderS if(event instanceof ChangeChannelTimeoutEvent) { ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event; - mStateMachineMap.get(event.getTimeslot()).setFadeTimeoutBuffer(timeout.getCallTimeout()); + mStateMachineMap.get(event.getTimeslot()).setFadeTimeoutBufferMilliseconds(timeout.getCallTimeoutMilliseconds()); } break; case CONTINUATION: diff --git a/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java b/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java index 20675e28..6b8da41b 100644 --- a/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java +++ b/src/main/java/io/github/dsheirer/channel/state/SingleChannelState.java @@ -109,19 +109,19 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder mStateMachine.addListener(mSquelchController); mStateMachine.setChannelType(mChannel.getChannelType()); mStateMachine.setIdentifierUpdateListener(mIdentifierCollection); - mStateMachine.setEndTimeoutBuffer(RESET_TIMEOUT_DELAY); + mStateMachine.setEndTimeoutBufferMilliseconds(RESET_TIMEOUT_DELAY); if(channel.getChannelType() == ChannelType.STANDARD) { - mStateMachine.setFadeTimeoutBuffer(FADE_TIMEOUT_DELAY); + mStateMachine.setFadeTimeoutBufferMilliseconds(FADE_TIMEOUT_DELAY); } else { final DecodeConfiguration decodeConfig = channel.getDecodeConfiguration(); final int fadeTimeoutSeconds = decodeConfig instanceof WithCallTimeout - ? ((WithCallTimeout) decodeConfig).getCallTimeout() + ? ((WithCallTimeout) decodeConfig).getCallTimeoutSeconds() : DecodeConfiguration.DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; - mStateMachine.setFadeTimeoutBuffer(fadeTimeoutSeconds * 1000); + mStateMachine.setFadeTimeoutBufferMilliseconds(fadeTimeoutSeconds * 1000); } } @@ -412,7 +412,7 @@ public class SingleChannelState extends AbstractChannelState implements IDecoder if(event instanceof ChangeChannelTimeoutEvent) { ChangeChannelTimeoutEvent timeout = (ChangeChannelTimeoutEvent)event; - mStateMachine.setFadeTimeoutBuffer(timeout.getCallTimeout()); + mStateMachine.setFadeTimeoutBufferMilliseconds(timeout.getCallTimeoutMilliseconds()); } case CONTINUATION: case DECODE: diff --git a/src/main/java/io/github/dsheirer/channel/state/StateMachine.java b/src/main/java/io/github/dsheirer/channel/state/StateMachine.java index 0b022bbc..70f8db57 100644 --- a/src/main/java/io/github/dsheirer/channel/state/StateMachine.java +++ b/src/main/java/io/github/dsheirer/channel/state/StateMachine.java @@ -42,9 +42,9 @@ public class StateMachine protected State mState = State.IDLE; protected long mFadeTimeout; - protected long mFadeTimeoutBuffer = 0; + protected long mFadeTimeoutBufferMilliseconds = 0; protected long mEndTimeout; - protected long mEndTimeoutBuffer = 0; + protected long mEndTimeoutBufferMilliseconds = 0; private int mTimeslot; private EnumSet mActiveStates; private Channel.ChannelType mChannelType = Channel.ChannelType.STANDARD; @@ -63,26 +63,42 @@ public class StateMachine mActiveStates = activeStates; } + /** + * Adds a state change listener + * @param listener to receive state change events + */ public void addListener(IStateMachineListener listener) { mStateMachineListeners.add(listener); } + /** + * Removes the state change listener + */ public void removeListener(IStateMachineListener listener) { mStateMachineListeners.remove(listener); } + /** + * Sets the listener to receive identifier update notifications (ie state identifier updates) + */ public void setIdentifierUpdateListener(Listener listener) { mIdentifierUpdateListener = listener; } + /** + * Sets the channel type for this state machine + */ public void setChannelType(Channel.ChannelType channelType) { mChannelType = channelType; } + /** + * Checks the state and transitions to FADE or TEARDOWN if timers have expired + */ public void checkState() { if(mActiveStates.contains(mState) && mFadeTimeout <= System.currentTimeMillis()) @@ -95,11 +111,17 @@ public class StateMachine } } + /** + * Current state of the state machine + */ public State getState() { return mState; } + /** + * Sets the state + */ public void setState(State state) { if(state == mState) @@ -173,6 +195,9 @@ public class StateMachine } } + /** + * Broadcasts a channel state identifier update + */ private void broadcast(ChannelStateIdentifier channelStateIdentifier) { if(mIdentifierUpdateListener != null) @@ -182,43 +207,70 @@ public class StateMachine } } + /** + * Updates the fade timeout to current time plus the fade timeout buffer value. + */ private void updateFadeTimeout() { - mFadeTimeout = System.currentTimeMillis() + mFadeTimeoutBuffer; + mFadeTimeout = System.currentTimeMillis() + mFadeTimeoutBufferMilliseconds; } + /** + * Manually sets the fade timeout + */ public void setFadeTimeout(long timeout) { mFadeTimeout = timeout; } + /** + * Fade timeout value + */ public long getFadeTimeout() { return mFadeTimeout; } - public void setFadeTimeoutBuffer(long buffer) + /** + * Sets the fade timeout buffer value. This value determines the maximum length of time the state machine + * can stay in any state (without an update) before automatically transitioning to FADE state. + * @param buffer in milliseconds + */ + public void setFadeTimeoutBufferMilliseconds(long buffer) { - mFadeTimeoutBuffer = buffer; + mFadeTimeoutBufferMilliseconds = buffer; updateFadeTimeout(); } + /** + * Updates the end timeout value to current system time plus the end timeout buffer value. + */ private void updateEndTimeout() { - mEndTimeout = System.currentTimeMillis() + mEndTimeoutBuffer; + mEndTimeout = System.currentTimeMillis() + mEndTimeoutBufferMilliseconds; } - public void setEndTimeoutBuffer(long buffer) + /** + * Sets the end timeout buffer value. This value is the maximum length of time that the channel can + * stay in the FADE state (without an update) before transitioning to a TEARDOWN state. + */ + public void setEndTimeoutBufferMilliseconds(long buffer) { - mEndTimeoutBuffer = buffer; + mEndTimeoutBufferMilliseconds = buffer; updateEndTimeout(); } + /** + * Sets the end timeout value + */ public void setEndTimeout(long endTimeout) { mEndTimeout = endTimeout; } + /** + * Current end timeout value + */ public long getEndTimeout() { return mEndTimeout; diff --git a/src/main/java/io/github/dsheirer/gui/playlist/channel/MPT1327ConfigurationEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/channel/MPT1327ConfigurationEditor.java index f078a384..b7eb9e4c 100644 --- a/src/main/java/io/github/dsheirer/gui/playlist/channel/MPT1327ConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/gui/playlist/channel/MPT1327ConfigurationEditor.java @@ -343,7 +343,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor } } - int callTimeout = decodeConfigMPT1327.getCallTimeout(); + int callTimeout = decodeConfigMPT1327.getCallTimeoutSeconds(); getCallTimeoutSpinner().getValueFactory().setValue(callTimeout); int channelPoolSize = decodeConfigMPT1327.getTrafficChannelPoolSize(); @@ -370,7 +370,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor config = new DecodeConfigMPT1327(); } - config.setCallTimeout(getCallTimeoutSpinner().getValue()); + config.setCallTimeoutSeconds(getCallTimeoutSpinner().getValue()); config.setTrafficChannelPoolSize(getTrafficChannelPoolSizeSpinner().getValue()); ChannelMap selected = getChannelMapComboBox().getSelectionModel().getSelectedItem(); diff --git a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java index 7239565f..2fed3147 100644 --- a/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java +++ b/src/main/java/io/github/dsheirer/module/decode/DecoderFactory.java @@ -227,11 +227,13 @@ public class DecoderFactory Sync sync = mptConfig.getSync(); modules.add(new MPT1327Decoder(sync)); - final int timeout = mptConfig.getCallTimeout() * 1000; + final int callTimeoutMilliseconds = mptConfig.getCallTimeoutSeconds() * 1000; + // Set max segment audio sample length slightly above call timeout to // not create a new segment if the processing chain finishes a bit after // actual call timeout. - modules.add(new AudioModule(aliasList, timeout + 5000)); + int maxAudioSegmentLengthMillis = (callTimeoutMilliseconds + 5000); + modules.add(new AudioModule(aliasList, maxAudioSegmentLengthMillis)); SourceType sourceType = channel.getSourceConfiguration().getSourceType(); if(sourceType == SourceType.TUNER || sourceType == SourceType.TUNER_MULTIPLE_FREQUENCIES) @@ -243,11 +245,11 @@ public class DecoderFactory { MPT1327TrafficChannelManager trafficChannelManager = new MPT1327TrafficChannelManager(channel, channelMap); modules.add(trafficChannelManager); - modules.add(new MPT1327DecoderState(trafficChannelManager, channelType, timeout)); + modules.add(new MPT1327DecoderState(trafficChannelManager, channelType, callTimeoutMilliseconds)); } else { - modules.add(new MPT1327DecoderState(channelType, timeout)); + modules.add(new MPT1327DecoderState(channelType, callTimeoutMilliseconds)); } //Add a channel rotation monitor when we have multiple control channel frequencies specified @@ -483,7 +485,7 @@ public class DecoderFactory case MPT1327: DecodeConfigMPT1327 originalMPT = (DecodeConfigMPT1327)config; DecodeConfigMPT1327 copyMPT = new DecodeConfigMPT1327(); - copyMPT.setCallTimeout(originalMPT.getCallTimeout()); + copyMPT.setCallTimeoutSeconds(originalMPT.getCallTimeoutSeconds()); copyMPT.setChannelMapName(originalMPT.getChannelMapName()); copyMPT.setSync(originalMPT.getSync()); copyMPT.setTrafficChannelPoolSize(originalMPT.getTrafficChannelPoolSize()); diff --git a/src/main/java/io/github/dsheirer/module/decode/config/WithCallTimeout.java b/src/main/java/io/github/dsheirer/module/decode/config/WithCallTimeout.java index a9c36249..1a0b442e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/config/WithCallTimeout.java +++ b/src/main/java/io/github/dsheirer/module/decode/config/WithCallTimeout.java @@ -30,5 +30,5 @@ public interface WithCallTimeout /** * @return call timeout in seconds */ - int getCallTimeout(); + int getCallTimeoutSeconds(); } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java index b06ccddd..f83ca02b 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/DecodeConfigMPT1327.java @@ -33,7 +33,7 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration implements WithCall private String mChannelMapName; private Sync mSync = Sync.NORMAL; - private int mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; + private int mCallTimeoutSeconds = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; private int mTrafficChannelPoolSize = TRAFFIC_CHANNEL_LIMIT_DEFAULT; public DecodeConfigMPT1327() @@ -69,9 +69,9 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration implements WithCall } @JacksonXmlProperty(isAttribute = true, localName = "call_timeout") - public int getCallTimeout() + public int getCallTimeoutSeconds() { - return mCallTimeout; + return mCallTimeoutSeconds; } /** @@ -79,15 +79,15 @@ public class DecodeConfigMPT1327 extends DecodeConfiguration implements WithCall * * @param timeout */ - public void setCallTimeout(int timeout) + public void setCallTimeoutSeconds(int timeout) { if(CALL_TIMEOUT_MINIMUM <= timeout && timeout <= CALL_TIMEOUT_MAXIMUM) { - mCallTimeout = timeout; + mCallTimeoutSeconds = timeout; } else { - mCallTimeout = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; + mCallTimeoutSeconds = DEFAULT_CALL_TIMEOUT_DELAY_SECONDS; } } diff --git a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java index 9ac05217..76fc5ffd 100644 --- a/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/mpt1327/MPT1327DecoderState.java @@ -42,7 +42,6 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.TreeSet; @@ -59,26 +58,30 @@ public class MPT1327DecoderState extends DecoderState private ChannelType mChannelType; private long mFrequency = 0; - private long mCallTimeout; + private long mCallTimeoutMilliseconds; private MPT1327TrafficChannelManager mMPT1327TrafficChannelManager; /** * Constructs an MPT-1327 decoder state with an optional traffic channel manager for allocating traffic channels - * when go to channel (GTC) messages are detected. + * when go to channel (GTC) messages are detected. This constructor assumes that channel type is STANDARD. + * + * @param trafficChannelManager for managing MPT1327 Traffic Channels + * @param callTimeoutMilliseconds for when traffic channels should automatically be stopped. */ - public MPT1327DecoderState(MPT1327TrafficChannelManager trafficChannelManager, ChannelType channelType, long callTimeout) + public MPT1327DecoderState(MPT1327TrafficChannelManager trafficChannelManager, ChannelType channelType, + long callTimeoutMilliseconds) { mMPT1327TrafficChannelManager = trafficChannelManager; mChannelType = channelType; - mCallTimeout = callTimeout; + mCallTimeoutMilliseconds = callTimeoutMilliseconds; } /** * Constructs an MPT1327 decoder state that does not allocate traffic channels */ - public MPT1327DecoderState(ChannelType channelType, long callTimeout) + public MPT1327DecoderState(ChannelType channelType, long callTimeoutMilliseconds) { - this(null, channelType, callTimeout); + this(null, channelType, callTimeoutMilliseconds); } @Override @@ -250,7 +253,7 @@ public class MPT1327DecoderState extends DecoderState { //When we receive a MAINT message and we're configured as a standard channel, apply the call // timeout specified by the user. Otherwise we'll be using the shorter default call timeout - broadcast(new ChangeChannelTimeoutEvent(this, mChannelType, mCallTimeout)); + broadcast(new ChangeChannelTimeoutEvent(this, mChannelType, mCallTimeoutMilliseconds)); MutableIdentifierCollection ic = new MutableIdentifierCollection(getIdentifierCollection().getIdentifiers()); ic.remove(IdentifierClass.USER);