mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 17:17:29 -05:00
Interim checkin for call recording.
This commit is contained in:
@@ -11,14 +11,17 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sample.Listener;
|
||||
import sample.real.RealBuffer;
|
||||
import sample.real.RealSampleListener;
|
||||
import sample.real.RealSampleProvider;
|
||||
import source.tuner.frequency.FrequencyCorrectionControl;
|
||||
import source.tuner.frequency.FrequencyCorrectionControl.FrequencyCorrectionResetListener;
|
||||
import dsp.gain.DirectGainControl;
|
||||
import dsp.gain.GainController;
|
||||
|
||||
public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
|
||||
RealSampleListener,
|
||||
Listener<RealBuffer>,
|
||||
RealSampleProvider,
|
||||
Instrumentable
|
||||
{
|
||||
@@ -202,8 +205,11 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
|
||||
|
||||
private RealSampleListener mListener;
|
||||
|
||||
private GainController mGainController;
|
||||
private DirectGainControl mGainController =
|
||||
new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
|
||||
|
||||
private FrequencyCorrectionControl mFrequencyCorrectionControl;
|
||||
private int mFrequencyAdjustmentRequested = 0;
|
||||
|
||||
/**
|
||||
* C4FM Symbol Filter
|
||||
@@ -218,11 +224,8 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
|
||||
* setting for this filter is 15.4 and that yields a symbol spread that
|
||||
* is centered on 2.0, ranging 1.92 to 2.08.
|
||||
*/
|
||||
public C4FMSymbolFilter( GainController gainController,
|
||||
FrequencyCorrectionControl frequencyControl )
|
||||
public C4FMSymbolFilter( FrequencyCorrectionControl frequencyControl )
|
||||
{
|
||||
mGainController = gainController;
|
||||
|
||||
mFrequencyCorrectionControl = frequencyControl;
|
||||
|
||||
/* Register for reset events, so we can reset internal frequency tracking */
|
||||
@@ -237,9 +240,36 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( RealBuffer buffer )
|
||||
{
|
||||
for( float sample: buffer.getSamples() )
|
||||
{
|
||||
receive( sample );
|
||||
}
|
||||
|
||||
/* If a frequency correction was requested during the processing of this
|
||||
* buffer, we'll apply the change and it will be reflected in the next
|
||||
* arriving buffer. Reset the lock on frequency correction and reset
|
||||
* the internal frequency correction tracker */
|
||||
if( mFrequencyAdjustmentRequested != 0 )
|
||||
{
|
||||
mFrequencyCorrectionControl.adjust( mFrequencyAdjustmentRequested );
|
||||
|
||||
mLog.debug( "Adjusting frequency [" + mFrequencyAdjustmentRequested +
|
||||
"] correction is now: " + mFrequencyCorrectionControl
|
||||
.getErrorCorrection() );
|
||||
|
||||
mFrequencyAdjustmentRequested = 0;
|
||||
|
||||
/* reset internal frequency error tracker */
|
||||
mCoarseFrequencyCorrection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void receive( float sample )
|
||||
{
|
||||
//TODO: limit frequency corrections to once per buffer !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
|
||||
sample = mGainController.correct( sample );
|
||||
|
||||
if( mReset )
|
||||
{
|
||||
mGainController.reset();
|
||||
@@ -353,15 +383,11 @@ public class C4FMSymbolFilter implements FrequencyCorrectionResetListener,
|
||||
|
||||
mFineFrequencyCorrection += ( symbolError * K_FINE_FREQUENCY );
|
||||
|
||||
/* send frequency correction */
|
||||
/* Queue a frequency adjustment (once per buffer) as needed */
|
||||
if( Math.abs( mCoarseFrequencyCorrection ) > COARSE_FREQUENCY_DEADBAND )
|
||||
{
|
||||
int adjustment = 500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 );
|
||||
|
||||
mFrequencyCorrectionControl.adjust( adjustment );
|
||||
|
||||
/* reset internal frequency error tracker */
|
||||
mCoarseFrequencyCorrection = 0;
|
||||
mFrequencyAdjustmentRequested =
|
||||
500 * ( mCoarseFrequencyCorrection > 0 ? 1 : -1 );
|
||||
}
|
||||
|
||||
if( mSymbolSpreadTap != null )
|
||||
|
||||
@@ -1501,6 +1501,7 @@ public class P25DecoderState extends DecoderState
|
||||
}
|
||||
else
|
||||
{
|
||||
/* These are alternate trunking control blocks in PDU format */
|
||||
switch( pdu.getOpcode() )
|
||||
{
|
||||
case ADJACENT_STATUS_BROADCAST:
|
||||
@@ -1583,7 +1584,7 @@ public class P25DecoderState extends DecoderState
|
||||
GroupDataChannelGrantExtended gdcge =
|
||||
(GroupDataChannelGrantExtended)pdu;
|
||||
|
||||
broadcast( new P25CallEvent.Builder( CallEventType.DATA_CALL )
|
||||
CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( gdcge.getTransmitChannel() )
|
||||
.details( ( gdcge.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
@@ -1591,7 +1592,9 @@ public class P25DecoderState extends DecoderState
|
||||
.frequency( gdcge.getDownlinkFrequency() )
|
||||
.from( gdcge.getSourceAddress() )
|
||||
.to( gdcge.getGroupAddress() )
|
||||
.build() );
|
||||
.build();
|
||||
|
||||
broadcast( new TrafficChannelAllocationEvent( this, callEvent ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1604,16 +1607,17 @@ public class P25DecoderState extends DecoderState
|
||||
GroupVoiceChannelGrantExplicit gvcge =
|
||||
(GroupVoiceChannelGrantExplicit)pdu;
|
||||
|
||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
||||
CallEvent callEvent = new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( gvcge.getTransmitChannel() )
|
||||
.details( "Trigger: PDU-GRP_V_CHAN_USER" +
|
||||
( gvcge.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
.details( ( gvcge.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( gvcge.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( gvcge.getDownlinkFrequency() )
|
||||
.from( gvcge.getSourceAddress() )
|
||||
.to( gvcge.getGroupAddress() )
|
||||
.build() );
|
||||
.build();
|
||||
|
||||
broadcast( new TrafficChannelAllocationEvent( this, callEvent ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1626,18 +1630,19 @@ public class P25DecoderState extends DecoderState
|
||||
IndividualDataChannelGrantExtended idcge =
|
||||
(IndividualDataChannelGrantExtended)pdu;
|
||||
|
||||
broadcast( new P25CallEvent.Builder( CallEventType.DATA_CALL )
|
||||
CallEvent callEvent = new P25CallEvent.Builder( CallEventType.DATA_CALL )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( idcge.getTransmitChannel() )
|
||||
.details( "Trigger:PDU-IND_DATA_CHAN_GRNT " +
|
||||
( idcge.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
.details( ( idcge.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||
( idcge.isEmergency() ? " EMERGENCY" : "") )
|
||||
.frequency( idcge.getDownlinkFrequency() )
|
||||
.from( idcge.getSourceWACN() + "-" +
|
||||
idcge.getSourceSystemID() + "-" +
|
||||
idcge.getSourceAddress() )
|
||||
.to( idcge.getTargetAddress() )
|
||||
.build() );
|
||||
.build();
|
||||
|
||||
broadcast( new TrafficChannelAllocationEvent( this, callEvent ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1773,7 +1778,7 @@ public class P25DecoderState extends DecoderState
|
||||
TelephoneInterconnectChannelGrantExplicit ticge =
|
||||
(TelephoneInterconnectChannelGrantExplicit)pdu;
|
||||
|
||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
||||
CallEvent callEvent = new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( ticge.getTransmitChannel() )
|
||||
.details( "Trigger: PDU-TEL_INT_V_CH_GRNT " +
|
||||
@@ -1783,7 +1788,9 @@ public class P25DecoderState extends DecoderState
|
||||
" CALL TIMER:" + ticge.getCallTimer() )
|
||||
.frequency( ticge.getDownlinkFrequency() )
|
||||
.from( ticge.getAddress() )
|
||||
.build() );
|
||||
.build();
|
||||
|
||||
broadcast( new TrafficChannelAllocationEvent( this, callEvent ) );
|
||||
break;
|
||||
case UNIT_REGISTRATION_RESPONSE:
|
||||
if( pdu instanceof UnitRegistrationResponseExtended )
|
||||
@@ -1851,7 +1858,7 @@ public class P25DecoderState extends DecoderState
|
||||
UnitToUnitVoiceChannelGrantExtended uuvcge =
|
||||
(UnitToUnitVoiceChannelGrantExtended)pdu;
|
||||
|
||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
||||
CallEvent uuCallEvent = new P25CallEvent.Builder( CallEventType.CALL )
|
||||
.aliasList( getAliasList() )
|
||||
.channel( uuvcge.getTransmitChannel() )
|
||||
.details( "Trigger:PDU-U2U_V-CH_GRNT " +
|
||||
@@ -1862,7 +1869,9 @@ public class P25DecoderState extends DecoderState
|
||||
uuvcge.getSourceSystemID() + "-" +
|
||||
uuvcge.getSourceID() )
|
||||
.to( uuvcge.getTargetAddress() )
|
||||
.build() );
|
||||
.build();
|
||||
|
||||
broadcast( new TrafficChannelAllocationEvent( this, uuCallEvent ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ package module.decode.p25;
|
||||
|
||||
import instrument.tap.Tap;
|
||||
import instrument.tap.stream.DibitTap;
|
||||
import instrument.tap.stream.FloatBufferTap;
|
||||
import instrument.tap.stream.FloatTap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -30,14 +31,12 @@ import org.slf4j.LoggerFactory;
|
||||
import sample.Listener;
|
||||
import sample.real.IRealBufferListener;
|
||||
import sample.real.RealBuffer;
|
||||
import sample.real.RealBufferToStreamConverter;
|
||||
import source.tuner.frequency.FrequencyCorrectionControl;
|
||||
import alias.AliasList;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import dsp.filter.FilterFactory;
|
||||
import dsp.filter.Window.WindowType;
|
||||
import dsp.filter.fir.real.RealFIRFilter_RB_RB;
|
||||
import dsp.gain.DirectGainControl;
|
||||
|
||||
public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
{
|
||||
@@ -45,7 +44,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
|
||||
/* Instrumentation Taps */
|
||||
private static final String INSTRUMENT_FILTER_OUTPUT = "Tap Point: Pre-Filter Output";
|
||||
private static final String INSTRUMENT_DGC_OUTPUT = "Tap Point: DGC Output";
|
||||
private static final String INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT = "Tap Point: Symbol Filter Output";
|
||||
private static final String INSTRUMENT_C4FM_SLICER_OUTPUT = "Tap Point: C4FM Slicer Output";
|
||||
|
||||
@@ -53,9 +51,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
|
||||
private List<Tap> mAvailableTaps;
|
||||
private RealFIRFilter_RB_RB mC4FMPreFilter;
|
||||
private DirectGainControl mDGC;
|
||||
private RealBufferToStreamConverter mStreamConverter =
|
||||
new RealBufferToStreamConverter();
|
||||
private FrequencyCorrectionControl mFrequencyCorrectionControl;
|
||||
private C4FMSymbolFilter mSymbolFilter;
|
||||
private C4FMSlicer mC4FMSlicer;
|
||||
@@ -82,22 +77,14 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
mC4FMPreFilter = new RealFIRFilter_RB_RB( FilterFactory.getLowPass(
|
||||
48000, 6750, 7500, 60, WindowType.HANNING, true ), 1.0f );
|
||||
|
||||
/* Convert buffers to a sample stream so that the symbol filter can
|
||||
* provide fine-grained gain control over individual samples */
|
||||
mC4FMPreFilter.setListener( mStreamConverter );
|
||||
|
||||
/* Apply gain remotely controlled by the downstream symbol filter */
|
||||
mDGC = new DirectGainControl( 15.0f, 0.1f, 35.0f, 0.3f );
|
||||
mStreamConverter.setListener( mDGC );
|
||||
|
||||
/* Issue tuned frequency correction commands, remotely controlled by the
|
||||
* downstream symbol filter */
|
||||
mFrequencyCorrectionControl = new FrequencyCorrectionControl(
|
||||
MAXIMUM_FREQUENCY_CORRECTION );
|
||||
|
||||
|
||||
/* Shape gain and frequency offsets to optimize sample stream */
|
||||
mSymbolFilter = new C4FMSymbolFilter( mDGC, mFrequencyCorrectionControl );
|
||||
mDGC.setListener( mSymbolFilter );
|
||||
mSymbolFilter = new C4FMSymbolFilter( mFrequencyCorrectionControl );
|
||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
||||
|
||||
/* Convert samples to symbols */
|
||||
mC4FMSlicer = new C4FMSlicer();
|
||||
@@ -119,12 +106,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
mC4FMPreFilter.dispose();
|
||||
mC4FMPreFilter = null;
|
||||
|
||||
mDGC.dispose();
|
||||
mDGC = null;
|
||||
|
||||
mStreamConverter.dispose();
|
||||
mStreamConverter = null;
|
||||
|
||||
mFrequencyCorrectionControl.dispose();
|
||||
mFrequencyCorrectionControl = null;
|
||||
|
||||
@@ -172,7 +153,6 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
mAvailableTaps = new ArrayList<Tap>();
|
||||
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_FILTER_OUTPUT, 0, 1.0f ) );
|
||||
mAvailableTaps.add( new FloatTap( INSTRUMENT_DGC_OUTPUT, 0, 1.0f ) );
|
||||
|
||||
if( mSymbolFilter != null )
|
||||
{
|
||||
@@ -200,14 +180,9 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_FILTER_OUTPUT:
|
||||
FloatTap filterOutput = (FloatTap)tap;
|
||||
mStreamConverter.setListener( filterOutput );
|
||||
filterOutput.setListener( mDGC );
|
||||
break;
|
||||
case INSTRUMENT_DGC_OUTPUT:
|
||||
FloatTap dgcTap = (FloatTap)tap;
|
||||
mDGC.setListener( dgcTap );
|
||||
dgcTap.setListener( mSymbolFilter );
|
||||
FloatBufferTap filterOutput = (FloatBufferTap)tap;
|
||||
mC4FMPreFilter.setListener( filterOutput );
|
||||
filterOutput.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||
FloatTap symbolTap = (FloatTap)tap;
|
||||
@@ -242,10 +217,7 @@ public class P25_C4FMDecoder extends P25Decoder implements IRealBufferListener
|
||||
switch( tap.getName() )
|
||||
{
|
||||
case INSTRUMENT_FILTER_OUTPUT:
|
||||
mStreamConverter.setListener( mDGC );
|
||||
break;
|
||||
case INSTRUMENT_DGC_OUTPUT:
|
||||
mDGC.setListener( mSymbolFilter );
|
||||
mC4FMPreFilter.setListener( mSymbolFilter );
|
||||
break;
|
||||
case INSTRUMENT_C4FM_SYMBOL_FILTER_OUTPUT:
|
||||
mSymbolFilter.setListener( mC4FMSlicer );
|
||||
|
||||
@@ -15,12 +15,12 @@ import org.slf4j.LoggerFactory;
|
||||
import controller.channel.ChannelEvent;
|
||||
import controller.channel.IChannelEventListener;
|
||||
import sample.Listener;
|
||||
import alias.Metadata;
|
||||
import audio.AudioFormats;
|
||||
import audio.AudioPacket;
|
||||
import audio.IAudioPacketProvider;
|
||||
import audio.metadata.AudioMetadata;
|
||||
import audio.metadata.IMetadataListener;
|
||||
import audio.metadata.Metadata;
|
||||
|
||||
public class P25AudioModule extends Module implements Listener<Message>,
|
||||
IAudioPacketProvider, IMessageListener, IChannelEventListener, IMetadataListener
|
||||
@@ -41,10 +41,12 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
||||
private AudioMetadata mAudioMetadata;
|
||||
private ChannelEventListener mChannelEventListener = new ChannelEventListener();
|
||||
|
||||
public P25AudioModule()
|
||||
public P25AudioModule( boolean record )
|
||||
{
|
||||
mSourceID = ++UNIQUE_ID;
|
||||
mAudioMetadata = new AudioMetadata( mSourceID );
|
||||
mAudioMetadata = new AudioMetadata( mSourceID, record );
|
||||
|
||||
loadConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,9 +62,21 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
public void reset()
|
||||
{
|
||||
loadConverter();
|
||||
mAudioMetadata.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user