#6 DMR Decoder (#947)

* #6 DMR decoder feature - work in progress

* #6 DMR Decoder.

* #6 DMR Decoder.  Code review updates.

Co-authored-by: Zhenyu Mao <maozhenyu@foxmail.com>
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
Denny Sheirer
2020-10-12 04:57:59 -04:00
committed by GitHub
parent b061db1189
commit 7eec82deee
436 changed files with 36258 additions and 2409 deletions

View File

@@ -85,11 +85,6 @@ public abstract class Source extends Module implements ISourceEventListener, ISo
*/
public abstract long getFrequency();
/**
* Process any cleanup actions to prepare for garbage collection of this source
*/
public abstract void dispose();
/**
* Registers the listener to receive overflow state changes. Use null argument to clear the listener
*/

View File

@@ -21,10 +21,15 @@
*/
package io.github.dsheirer.source;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.EnumSet;
public class SourceEvent
{
private final static Logger mLog = LoggerFactory.getLogger(SourceEvent.class);
public enum Event
{
NOTIFICATION_CHANNEL_COUNT_CHANGE,
@@ -46,6 +51,7 @@ public class SourceEvent
REQUEST_CHANNEL_FREQUENCY_CORRECTION_CHANGE,
REQUEST_FREQUENCY_CHANGE,
REQUEST_FREQUENCY_ROTATION,
REQUEST_FREQUENCY_SELECTION,
REQUEST_SOURCE_DISPOSE,
REQUEST_START_SAMPLE_STREAM,
REQUEST_STOP_SAMPLE_STREAM;
@@ -388,6 +394,15 @@ public class SourceEvent
return new SourceEvent(Event.REQUEST_FREQUENCY_ROTATION);
}
/**
* Creates a request to cycle to a specific frequency. This is normally used for decoders to request the
* next frequency in a list when a multiple-frequency source configuration is defined.
*/
public static SourceEvent frequencySelectionRequest()
{
return new SourceEvent(Event.REQUEST_FREQUENCY_SELECTION);
}
/**
* Creates a notification that the request to rotate the source frequency to the next frequency in the list
* was successful.

View File

@@ -95,7 +95,7 @@ public class SourceManager
if(config instanceof SourceConfigTunerMultipleFrequency)
{
SourceConfigTunerMultipleFrequency sourceConfigTuner = (SourceConfigTunerMultipleFrequency)config;
TunerChannel tunerChannel = sourceConfigTuner.getFirstTunerChannel(channelSpecification.getBandwidth());
TunerChannel tunerChannel = sourceConfigTuner.getTunerChannel(channelSpecification.getBandwidth());
String preferredTuner = sourceConfigTuner.getPreferredTuner();
Source source = mTunerModel.getSource(tunerChannel, channelSpecification, preferredTuner);

View File

@@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import io.github.dsheirer.source.SourceType;
import io.github.dsheirer.source.tuner.channel.TunerChannel;
import io.github.dsheirer.source.tuner.channel.rotation.ChannelRotationMonitor;
import java.util.ArrayList;
import java.util.List;
@@ -37,6 +38,8 @@ public class SourceConfigTunerMultipleFrequency extends SourceConfiguration
{
private List<Long> mFrequencies = new ArrayList<>();
private String mPreferredTuner;
private Long mPreferredFrequency;
private int mFrequencyRotationDelay = ChannelRotationMonitor.CHANNEL_ROTATION_DELAY_MINIMUM;
public SourceConfigTunerMultipleFrequency()
{
@@ -69,6 +72,37 @@ public class SourceConfigTunerMultipleFrequency extends SourceConfiguration
return mFrequencies.size() > 1;
}
/**
* Preferred frequency to start first for this configuration
*/
@JsonIgnore
public long getPreferredFrequency()
{
if(mPreferredFrequency != null)
{
return mPreferredFrequency;
}
else if(mFrequencies.size() > 0)
{
return mFrequencies.get(0);
}
return 0l;
}
/**
* Sets which is the preferred frequency to use for this config when it's started
* @param frequency to use first
*/
public void setPreferredFrequency(long frequency)
{
//Only set the frequency if it is one of the frequencies in the list
if(mFrequencies.contains(frequency))
{
mPreferredFrequency = frequency;
}
}
/**
* Adds a frequency to the list
*/
@@ -113,15 +147,43 @@ public class SourceConfigTunerMultipleFrequency extends SourceConfiguration
}
@JsonIgnore
public TunerChannel getFirstTunerChannel(int bandwidth)
public TunerChannel getTunerChannel(int bandwidth)
{
if(getFrequencies().size() > 0)
return new TunerChannel(getPreferredFrequency(), bandwidth);
}
/**
* Channel rotation delay. This setting is used when multiple channel frequencies are defined in the source
* config and controls how long the decoder will remaining on each frequency until the channel is identified as
* active or the channel is identified as inactive and a change frequency request is issued.
*
* Note: this value is ignored when the source config contains a single frequency.
*
* @return channel rotation delay in milliseconds.
*/
@JacksonXmlProperty(isAttribute = true, localName = "frequency_rotation_delay")
public int getFrequencyRotationDelay()
{
return mFrequencyRotationDelay;
}
/**
* Sets the channel rotation delay.
* @param frequencyRotationDelay in milliseconds.
*/
public void setFrequencyRotationDelay(int frequencyRotationDelay)
{
if(frequencyRotationDelay < ChannelRotationMonitor.CHANNEL_ROTATION_DELAY_MINIMUM)
{
return new TunerChannel(getFrequencies().get(0), bandwidth);
mFrequencyRotationDelay = ChannelRotationMonitor.CHANNEL_ROTATION_DELAY_MINIMUM;
}
else if(frequencyRotationDelay > ChannelRotationMonitor.CHANNEL_ROTATION_DELAY_MAXIMUM)
{
mFrequencyRotationDelay = ChannelRotationMonitor.CHANNEL_ROTATION_DELAY_MAXIMUM;
}
else
{
return new TunerChannel(0l, bandwidth);
mFrequencyRotationDelay = frequencyRotationDelay;
}
}
}

View File

@@ -140,11 +140,4 @@ public class RealMixerSource extends RealSource
{
mFrequency = frequency;
}
@Override
public void dispose()
{
mMixerReader.dispose();
}
}

View File

@@ -20,6 +20,7 @@
package io.github.dsheirer.source.tuner.channel;
import com.google.common.eventbus.Subscribe;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.sample.buffer.ReusableComplexBuffer;
import io.github.dsheirer.source.Source;
@@ -27,10 +28,12 @@ import io.github.dsheirer.source.SourceEvent;
import io.github.dsheirer.source.SourceException;
import io.github.dsheirer.source.heartbeat.Heartbeat;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.source.tuner.channel.rotation.FrequencyLockChangeRequest;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -47,6 +50,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
private TunerModel mTunerModel;
private TunerChannelSource mTunerChannelSource;
private List<Long> mFrequencies;
private List<Long> mLockedFrequencies = new ArrayList<>();
private int mFrequencyListPointer = 0;
private ChannelSpecification mChannelSpecification;
private Listener<ReusableComplexBuffer> mReusableComplexBufferListener;
@@ -70,29 +74,34 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
}
/**
* Cycles this source to use the next frequency in the list
* Cycles this source to use the next frequency in the list. If no other frequencies are available,
* because of frequency locking, ignore the rotate request.
*/
private void nextFrequency()
private void rotate()
{
if(mChangingChannels.compareAndSet(false, true))
{
//Only change if we have more than one frequency specified
if(mFrequencies.size() > 0)
{
if(mTunerChannelSource != null)
{
//Shutdown the existing tuner channel source
mTunerChannelSource.stop();
mTunerChannelSource.removeListener(mReusableComplexBufferListener);
mTunerChannelSource.removeSourceEventListener();
mTunerChannelSource.removeHeartbeatListener(mHeartbeatListener);
mTunerChannelSource.dispose();
mTunerChannelSource = null;
}
long frequency = getNextFrequency();
//Request the next tuner channel source
getNextSource();
if(frequency == 0)
{
mChangingChannels.set(false);
return;
}
if(mTunerChannelSource != null)
{
//Shutdown the existing tuner channel source
mTunerChannelSource.stop();
mTunerChannelSource.removeListener(mReusableComplexBufferListener);
mTunerChannelSource.removeSourceEventListener();
mTunerChannelSource.removeHeartbeatListener(mHeartbeatListener);
mTunerChannelSource.dispose();
mTunerChannelSource = null;
}
//Request the next tuner channel source
getNextSource(getTunerChannel(frequency));
}
}
@@ -103,11 +112,10 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
* Note: if this channel source is shutdown by the external consumer, the mStarted flag will be set to false and
* the persistent attempts will stop.
*/
private void getNextSource()
private void getNextSource(TunerChannel nextChannel)
{
if(mStarted)
{
TunerChannel nextChannel = getNextChannel();
Source source = mTunerModel.getSource(nextChannel, mChannelSpecification, mPreferredTuner);
if(source instanceof TunerChannelSource)
@@ -117,7 +125,9 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
mTunerChannelSource.setListener(mReusableComplexBufferListener);
mTunerChannelSource.addHeartbeatListener(mHeartbeatListener);
mTunerChannelSource.start();
mTunerChannel = nextChannel;
mChangingChannels.set(false);
getSourceEventListener().receive(SourceEvent.frequencyRotationSuccessNotification(this, nextChannel.getFrequency()));
}
@@ -126,7 +136,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
if(mTunerChannelSource == null)
{
getSourceEventListener().receive(SourceEvent.frequencyRotationFailureNotification(this, nextChannel.getFrequency()));
ThreadPool.SCHEDULED.schedule(() -> getNextSource(), 1, TimeUnit.SECONDS);
ThreadPool.SCHEDULED.schedule(() -> getNextSource(getTunerChannel(getNextFrequency())), 500, TimeUnit.MILLISECONDS);
}
}
}
@@ -151,23 +161,70 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
{
mTunerChannelSource.stop();
mTunerChannelSource.removeSourceEventListener();
mTunerChannelSource = null;
}
}
/**
* Processes requests to lock or unlock frequencies for this source that are received over the processing chain
* event bus. A locked frequency will not be used in the frequency rotation list until it is unlocked.
*
* @param request to lock or unlock a frequency
*/
@Subscribe
public void process(FrequencyLockChangeRequest request)
{
if(request.isLockRequest() && !mLockedFrequencies.contains(request.getFrequency()))
{
mLockedFrequencies.add(request.getFrequency());
}
else if(request.isUnlockRequest() && mLockedFrequencies.contains(request.getFrequency()))
{
mLockedFrequencies.remove(request.getFrequency());
}
}
/**
* Identifies the next frequency in the list to use, while respecting the locked frequencies list.
*
* @return next frequency or 0 if there currently are no other frequencies than the frequency currently in use.
*/
private long getNextFrequency()
{
if(mFrequencies.size() <= 1)
{
return 0;
}
int attempts = 0;
mFrequencyListPointer = ++mFrequencyListPointer % mFrequencies.size();
long frequency = mFrequencies.get(mFrequencyListPointer);
while((mLockedFrequencies.contains(frequency) || frequency == getFrequency()) && attempts < mFrequencies.size())
{
//If we loop through the entire list back to the current frequency, return 0;
if(frequency == getFrequency())
{
return 0;
}
mFrequencyListPointer = ++mFrequencyListPointer % mFrequencies.size();
frequency = mFrequencies.get(mFrequencyListPointer);
attempts++;
}
return frequency;
}
/**
* Provides the next tuner channel from the frequency list.
*/
private TunerChannel getNextChannel()
private TunerChannel getTunerChannel(long frequency)
{
mFrequencyListPointer++;
if(mFrequencyListPointer >= mFrequencies.size())
{
mFrequencyListPointer = 0;
}
long frequency = mFrequencies.get(mFrequencyListPointer);
return new TunerChannel(frequency, mChannelSpecification.getBandwidth());
}
@@ -291,7 +348,7 @@ public class MultiFrequencyTunerChannelSource extends TunerChannelSource
{
if(sourceEvent.getEvent() == SourceEvent.Event.REQUEST_FREQUENCY_ROTATION)
{
nextFrequency();
rotate();
}
else if(mTunerChannelSource != null)
{

View File

@@ -40,7 +40,7 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
private final static Logger mLog = LoggerFactory.getLogger(TunerChannelSource.class);
private static final long BUFFER_PROCESSOR_RUN_INTERVAL_MILLISECONDS = 50;
private SourceEventListenerToProcessorAdapter mConsumerSourceEventListenerAdapter;
private TunerChannel mTunerChannel;
protected TunerChannel mTunerChannel;
private Listener<SourceEvent> mProducerSourceEventListener;
private Listener<SourceEvent> mConsumerSourceEventListener;
private ScheduledIntervalProcessor mScheduledIntervalProcessor = new ScheduledIntervalProcessor();
@@ -117,12 +117,6 @@ public abstract class TunerChannelSource extends ComplexSource implements ISourc
return mTunerChannel;
}
@Override
public void dispose()
{
stop();
}
/**
* Starts this tuner channel source producing sample stream.
*/

View File

@@ -0,0 +1,49 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.channel.rotation;
import io.github.dsheirer.channel.state.State;
import io.github.dsheirer.module.ModuleEventBusMessage;
/**
* Request to add a channel state to the list of active channel states monitored by the channel rotation monitor.
*/
public class AddChannelRotationActiveStateRequest extends ModuleEventBusMessage
{
private State mState;
/**
* Constructs an instance
* @param state to add
*/
public AddChannelRotationActiveStateRequest(State state)
{
mState = state;
}
/**
* State to add to the list of active states
* @return state
*/
public State getState()
{
return mState;
}
}

View File

@@ -1,32 +1,28 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 Dennis Sheirer
*
* * ******************************************************************************
* * Copyright (C) 2014-2019 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 <http://www.gnu.org/licenses/>
* * *****************************************************************************
* 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.channel;
package io.github.dsheirer.source.tuner.channel.rotation;
import com.google.common.eventbus.Subscribe;
import io.github.dsheirer.channel.state.DecoderStateEvent;
import io.github.dsheirer.channel.state.IDecoderStateEventListener;
import io.github.dsheirer.channel.state.State;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.module.Module;
import io.github.dsheirer.preference.PreferenceType;
import io.github.dsheirer.preference.UserPreferences;
@@ -43,36 +39,38 @@ import java.util.concurrent.TimeUnit;
/**
* Monitors channel state to detect when a channel is not in an identified active state and issues a request to rotate
* the next channel frequency in the list. This class depends on the ChannelState to provide a continuous
* stream of channel active/inactive messaging in the form of DecoderStateEvents.
* to the next channel frequency in the list. This class depends on the ChannelState providing a continuous
* stream of channel state notification events in the form of DecoderStateEvents.
*/
public class ChannelRotationMonitor extends Module implements ISourceEventProvider, IDecoderStateEventListener,
Listener<DecoderStateEvent>
{
private final static Logger mLog = LoggerFactory.getLogger(ChannelRotationMonitor.class);
public static final int CHANNEL_ROTATION_DELAY_MINIMUM = 200;
public static final int CHANNEL_ROTATION_DELAY_MAXIMUM = 2000;
private final static Logger mLog = LoggerFactory.getLogger(ChannelRotationMonitor.class);
private UserPreferences mUserPreferences;
private Collection<State> mActiveStates;
private ScheduledFuture<?> mScheduledFuture;
private Listener<SourceEvent> mSourceEventListener;
private long mRotationDelay;
private boolean mActive;
private long mInactiveTimestamp = System.currentTimeMillis();
private long mLastActiveTimestamp = System.currentTimeMillis();
private boolean mEnabled = true;
/**
* Constructs a channel rotation monitor.
*
* Constructs a channel rotation monitor that uses the specified rotation delay.
* @param activeStates to monitor
* @param userPreferences to receive updates for rotation delay value from user preferences
* @param rotationDelay specifies how long to remain on each frequency before rotating (in milliseconds).
*/
public ChannelRotationMonitor(Collection<State> activeStates, UserPreferences userPreferences)
public ChannelRotationMonitor(Collection<State> activeStates, long rotationDelay)
{
mActiveStates = activeStates;
mUserPreferences = userPreferences;
mRotationDelay = mUserPreferences.getChannelMultiFrequencyPreference().getRotationDelay();
mRotationDelay = rotationDelay;
//Register to receive user preference updates
MyEventBus.getEventBus().register(this);
if(mRotationDelay == 0)
{
mRotationDelay = 200;
}
}
/**
@@ -100,21 +98,40 @@ public class ChannelRotationMonitor extends Module implements ISourceEventProvid
}
@Override
public void receive(DecoderStateEvent decoderStateEvent)
public void receive(DecoderStateEvent event)
{
if(decoderStateEvent.getEvent() == DecoderStateEvent.Event.NOTIFICATION_CHANNEL_ACTIVE_STATE)
switch(event.getEvent())
{
mActive = true;
case NOTIFICATION_CHANNEL_STATE:
if(mActiveStates.contains(event.getState()))
{
mLastActiveTimestamp = System.currentTimeMillis();
}
break;
}
else if(decoderStateEvent.getEvent() == DecoderStateEvent.Event.NOTIFICATION_CHANNEL_INACTIVE_STATE)
{
if(mActive)
{
//If we're toggling from active to inactive, update the timestamp,
mInactiveTimestamp = System.currentTimeMillis();
}
}
mActive = false;
/**
* Processes a request to disable this monitor instance.
* @param request to disable
*/
@Subscribe
public void disable(DisableChannelRotationMonitorRequest request)
{
mEnabled = false;
stop();
}
/**
* Processes a request to add an active state to the list of monitored active states.
* @param request to add
*/
@Subscribe
public void addActiveState(AddChannelRotationActiveStateRequest request)
{
if(!mActiveStates.contains(request.getState()))
{
mActiveStates.add(request.getState());
}
}
@@ -124,11 +141,11 @@ public class ChannelRotationMonitor extends Module implements ISourceEventProvid
*/
private void checkState()
{
if(mSourceEventListener != null && !mActive &&
((mInactiveTimestamp + mRotationDelay) < System.currentTimeMillis()))
if(mEnabled && mSourceEventListener != null &&
((mLastActiveTimestamp + mRotationDelay) < System.currentTimeMillis()))
{
mSourceEventListener.receive(SourceEvent.frequencyRotationRequest());
mInactiveTimestamp = System.currentTimeMillis();
mLastActiveTimestamp = System.currentTimeMillis();
}
}
@@ -148,7 +165,6 @@ public class ChannelRotationMonitor extends Module implements ISourceEventProvid
@Override
public void reset()
{
}
@Override
@@ -156,7 +172,19 @@ public class ChannelRotationMonitor extends Module implements ISourceEventProvid
{
if(mScheduledFuture == null)
{
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(() -> checkState(), 1, 1, TimeUnit.SECONDS);
Runnable runnable = () -> {
try
{
checkState();
}
catch(Throwable t)
{
mLog.warn("Error while checking state", t);
}
};
mScheduledFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(runnable, mRotationDelay,
mRotationDelay / 2, TimeUnit.MILLISECONDS);
}
}
@@ -166,12 +194,8 @@ public class ChannelRotationMonitor extends Module implements ISourceEventProvid
if(mScheduledFuture != null)
{
mScheduledFuture.cancel(true);
mScheduledFuture = null;
}
}
@Override
public void dispose()
{
}
}

View File

@@ -0,0 +1,29 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.channel.rotation;
import io.github.dsheirer.module.ModuleEventBusMessage;
/**
* Request to disable the channel rotation monitor.
*/
public class DisableChannelRotationMonitorRequest extends ModuleEventBusMessage
{
}

View File

@@ -0,0 +1,94 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2020 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 <http://www.gnu.org/licenses/>
* ****************************************************************************
*/
package io.github.dsheirer.source.tuner.channel.rotation;
import io.github.dsheirer.module.ModuleEventBusMessage;
/**
* Request to lock or unlock a frequency from use.
*/
public class FrequencyLockChangeRequest extends ModuleEventBusMessage
{
private long mFrequency;
private boolean mLock;
/**
* Constructs an instance
* @param frequency for the request
* @param lock true if this is a lock or false if this is an unlock
*/
public FrequencyLockChangeRequest(long frequency, boolean lock)
{
mFrequency = frequency;
mLock = lock;
}
/**
* Frequency for this request
*/
public long getFrequency()
{
return mFrequency;
}
/**
* Indicates if this request is to lock the frequency
*/
public boolean isLockRequest()
{
return mLock;
}
/**
* Indicates if this request is to unlock the frequency
*/
public boolean isUnlockRequest()
{
return !mLock;
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("FREQUENCY ").append(isLockRequest() ? "LOCK" : "UNLOCK").append(" REQUEST: ").append(getFrequency());
return sb.toString();
}
/**
* Utility method to create a lock request
* @param frequency to lock
* @return request
*/
public static FrequencyLockChangeRequest lock(long frequency)
{
return new FrequencyLockChangeRequest(frequency, true);
}
/**
* Utility method to create an unlock request
* @param frequency to unlock
* @return request
*/
public static FrequencyLockChangeRequest unlock(long frequency)
{
return new FrequencyLockChangeRequest(frequency, false);
}
}

View File

@@ -297,12 +297,6 @@ public class ComplexWaveSource extends ComplexSource implements IControllableFil
mListener = null;
}
@Override
public void dispose()
{
mListener = null;
}
@Override
public File getFile()
{

View File

@@ -256,12 +256,6 @@ public class RealWaveSource extends RealSource implements IControllableFileSourc
mListener = null;
}
@Override
public void dispose()
{
mListener = null;
}
@Override
public File getFile()
{