mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
P25 Decoder updates - work in progress.
Updated jmbe library to work with version 0.3.1
This commit is contained in:
@@ -24,6 +24,6 @@
|
|||||||
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
|
<classpathentry kind="lib" path="imports/logback-classic-1.1.2.jar"/>
|
||||||
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
|
<classpathentry kind="lib" path="imports/logback-core-1.1.2.jar"/>
|
||||||
<classpathentry kind="lib" path="imports/commons-io-2.4.jar"/>
|
<classpathentry kind="lib" path="imports/commons-io-2.4.jar"/>
|
||||||
<classpathentry kind="lib" path="imports/jmbe-interface-0.3.0.jar"/>
|
<classpathentry kind="lib" path="imports/jmbe-interface-0.3.1.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
Binary file not shown.
@@ -42,7 +42,7 @@ import controller.config.Configuration;
|
|||||||
public abstract class DecodeConfiguration extends Configuration
|
public abstract class DecodeConfiguration extends Configuration
|
||||||
{
|
{
|
||||||
public static final int DEFAULT_CALL_TIMEOUT_SECONDS = 45;
|
public static final int DEFAULT_CALL_TIMEOUT_SECONDS = 45;
|
||||||
public static final int CALL_TIMEOUT_MINIMUM = 10;
|
public static final int CALL_TIMEOUT_MINIMUM = 1;
|
||||||
public static final int CALL_TIMEOUT_MAXIMUM = 300; //5 minutes
|
public static final int CALL_TIMEOUT_MAXIMUM = 300; //5 minutes
|
||||||
|
|
||||||
public static final int TRAFFIC_CHANNEL_LIMIT_DEFAULT = 3;
|
public static final int TRAFFIC_CHANNEL_LIMIT_DEFAULT = 3;
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ public abstract class CallEvent implements Comparable<CallEvent>
|
|||||||
ENCRYPTED_CALL( "Encrypted Call" ),
|
ENCRYPTED_CALL( "Encrypted Call" ),
|
||||||
FUNCTION( "Function" ),
|
FUNCTION( "Function" ),
|
||||||
GPS( "GPS" ),
|
GPS( "GPS" ),
|
||||||
|
GROUP_CALL( "Group Call" ),
|
||||||
ID_ANI( "ANI" ),
|
ID_ANI( "ANI" ),
|
||||||
ID_UNIQUE( "Unique ID" ),
|
ID_UNIQUE( "Unique ID" ),
|
||||||
PAGE( "Page" ),
|
PAGE( "Page" ),
|
||||||
@@ -283,7 +284,8 @@ public abstract class CallEvent implements Comparable<CallEvent>
|
|||||||
SDM( "Short Data Message" ),
|
SDM( "Short Data Message" ),
|
||||||
STATION_ID( "Station ID" ),
|
STATION_ID( "Station ID" ),
|
||||||
STATUS( "Status" ),
|
STATUS( "Status" ),
|
||||||
TELEPHONE_CALL( "Telephone Call" ),
|
TELEPHONE_INTERCONNECT( "Telephone Interconnect" ),
|
||||||
|
UNIT_TO_UNIT_CALL( "Unit To Unit Call" ),
|
||||||
UNKNOWN( "Unknown" ),
|
UNKNOWN( "Unknown" ),
|
||||||
INVALID( "Invalid" );
|
INVALID( "Invalid" );
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private JLabel mProtocol;
|
private JLabel mProtocol;
|
||||||
private JLabel mFrom = new JLabel( " " );
|
|
||||||
private JLabel mFromAlias = new JLabel( " " );
|
|
||||||
|
|
||||||
private JLabel mNAC = new JLabel( "NAC:" );
|
|
||||||
private JLabel mTo = new JLabel( " " );
|
private JLabel mTo = new JLabel( " " );
|
||||||
private JLabel mToAlias = new JLabel( " " );
|
private JLabel mToAlias = new JLabel( " " );
|
||||||
|
|
||||||
|
private JLabel mNAC = new JLabel( "NAC:" );
|
||||||
|
private JLabel mFrom = new JLabel( " " );
|
||||||
|
private JLabel mFromAlias = new JLabel( " " );
|
||||||
|
|
||||||
private JLabel mSystem = new JLabel( "SYS:" );
|
private JLabel mSystem = new JLabel( "SYS:" );
|
||||||
private JLabel mSite = new JLabel( "Site:" );
|
private JLabel mSite = new JLabel( "Site:" );
|
||||||
private JLabel mSiteAlias = new JLabel( "" );
|
private JLabel mSiteAlias = new JLabel( "" );
|
||||||
@@ -65,21 +65,21 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
mProtocol.setFont( mFontDecoder );
|
mProtocol.setFont( mFontDecoder );
|
||||||
mProtocol.setForeground( mColorLabelDecoder );
|
mProtocol.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
mFrom.setFont( mFontDecoder );
|
|
||||||
mFrom.setForeground( mColorLabelDecoder );
|
|
||||||
|
|
||||||
mFromAlias.setFont( mFontDecoder );
|
|
||||||
mFromAlias.setForeground( mColorLabelDecoder );
|
|
||||||
|
|
||||||
mNAC.setFont( mFontDetails );
|
|
||||||
mNAC.setForeground( mColorLabelDecoder );
|
|
||||||
|
|
||||||
mTo.setFont( mFontDecoder );
|
mTo.setFont( mFontDecoder );
|
||||||
mTo.setForeground( mColorLabelDecoder );
|
mTo.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
mToAlias.setFont( mFontDecoder );
|
mToAlias.setFont( mFontDecoder );
|
||||||
mToAlias.setForeground( mColorLabelDecoder );
|
mToAlias.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
|
mNAC.setFont( mFontDetails );
|
||||||
|
mNAC.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
|
mFrom.setFont( mFontDecoder );
|
||||||
|
mFrom.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
|
mFromAlias.setFont( mFontDecoder );
|
||||||
|
mFromAlias.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
mSystem.setFont( mFontDetails );
|
mSystem.setFont( mFontDetails );
|
||||||
mSystem.setForeground( mColorLabelDecoder );
|
mSystem.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
@@ -90,13 +90,13 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
mSite.setForeground( mColorLabelDecoder );
|
mSite.setForeground( mColorLabelDecoder );
|
||||||
|
|
||||||
add( mProtocol );
|
add( mProtocol );
|
||||||
add( mFrom );
|
|
||||||
add( mFromAlias, "wrap" );
|
|
||||||
|
|
||||||
add( mNAC );
|
|
||||||
add( mTo );
|
add( mTo );
|
||||||
add( mToAlias, "wrap" );
|
add( mToAlias, "wrap" );
|
||||||
|
|
||||||
|
add( mNAC );
|
||||||
|
add( mFrom );
|
||||||
|
add( mFromAlias, "wrap" );
|
||||||
|
|
||||||
add( mSystem );
|
add( mSystem );
|
||||||
add( mSite );
|
add( mSite );
|
||||||
add( mSiteAlias, "wrap" );
|
add( mSiteAlias, "wrap" );
|
||||||
@@ -133,7 +133,14 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
mSiteAlias.setText( state.getSiteAlias() );
|
mSiteAlias.setText( state.getSiteAlias() );
|
||||||
break;
|
break;
|
||||||
case FROM_TALKGROUP:
|
case FROM_TALKGROUP:
|
||||||
mFrom.setText( state.getFromTalkgroup() );
|
if( state.getFromTalkgroup() == null )
|
||||||
|
{
|
||||||
|
mFrom.setText( " " );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFrom.setText( state.getFromTalkgroup() );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case FROM_TALKGROUP_ALIAS:
|
case FROM_TALKGROUP_ALIAS:
|
||||||
Alias from = state.getFromAlias();
|
Alias from = state.getFromAlias();
|
||||||
@@ -146,12 +153,19 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mFromAlias.setText( null );
|
mFromAlias.setText( " " );
|
||||||
mFromAlias.setIcon( null );
|
mFromAlias.setIcon( null );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TO_TALKGROUP:
|
case TO_TALKGROUP:
|
||||||
mTo.setText( state.getToTalkgroup() );
|
if( state.getToTalkgroup() == null )
|
||||||
|
{
|
||||||
|
mTo.setText( " " );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTo.setText( state.getToTalkgroup() );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case TO_TALKGROUP_ALIAS:
|
case TO_TALKGROUP_ALIAS:
|
||||||
Alias to = state.getToAlias();
|
Alias to = state.getToAlias();
|
||||||
@@ -164,7 +178,7 @@ public class P25DecoderPanel extends DecoderPanel
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mToAlias.setText( null );
|
mToAlias.setText( " " );
|
||||||
mToAlias.setIcon( null );
|
mToAlias.setIcon( null );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ import module.decode.p25.message.tsbk.osp.voice.UnitToUnitAnswerRequest;
|
|||||||
import module.decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrant;
|
import module.decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrant;
|
||||||
import module.decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrantUpdate;
|
import module.decode.p25.message.tsbk.osp.voice.UnitToUnitVoiceChannelGrantUpdate;
|
||||||
import module.decode.p25.reference.IPProtocol;
|
import module.decode.p25.reference.IPProtocol;
|
||||||
|
import module.decode.p25.reference.LinkControlOpcode;
|
||||||
import module.decode.p25.reference.Response;
|
import module.decode.p25.reference.Response;
|
||||||
import module.decode.p25.reference.Service;
|
import module.decode.p25.reference.Service;
|
||||||
import module.decode.p25.reference.Vendor;
|
import module.decode.p25.reference.Vendor;
|
||||||
@@ -128,6 +129,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import alias.Alias;
|
import alias.Alias;
|
||||||
import alias.AliasList;
|
import alias.AliasList;
|
||||||
|
import audio.metadata.Metadata;
|
||||||
|
import audio.metadata.MetadataType;
|
||||||
import controller.channel.Channel.ChannelType;
|
import controller.channel.Channel.ChannelType;
|
||||||
|
|
||||||
public class P25DecoderState extends DecoderState
|
public class P25DecoderState extends DecoderState
|
||||||
@@ -169,10 +172,12 @@ public class P25DecoderState extends DecoderState
|
|||||||
private String mCurrentChannel = "CURRENT";
|
private String mCurrentChannel = "CURRENT";
|
||||||
private long mCurrentChannelFrequency = 0;
|
private long mCurrentChannelFrequency = 0;
|
||||||
|
|
||||||
private P25CallEvent mCurrentCallEvent;
|
|
||||||
private ChannelType mChannelType;
|
private ChannelType mChannelType;
|
||||||
private Modulation mModulation;
|
private Modulation mModulation;
|
||||||
|
|
||||||
|
private P25CallEvent mCurrentCallEvent;
|
||||||
|
private List<String> mCallDetectTalkgroups = new ArrayList<>();
|
||||||
|
|
||||||
public P25DecoderState( AliasList aliasList,
|
public P25DecoderState( AliasList aliasList,
|
||||||
ChannelType channelType,
|
ChannelType channelType,
|
||||||
Modulation modulation )
|
Modulation modulation )
|
||||||
@@ -221,8 +226,26 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void resetState()
|
private void resetState()
|
||||||
{
|
{
|
||||||
updateFrom( null );
|
mFromTalkgroup = null;
|
||||||
updateTo( null );
|
broadcast( ChangedAttribute.FROM_TALKGROUP );
|
||||||
|
|
||||||
|
mFromAlias = null;
|
||||||
|
broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
|
||||||
|
|
||||||
|
mToTalkgroup = null;
|
||||||
|
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||||
|
|
||||||
|
mToAlias = null;
|
||||||
|
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.clear();
|
||||||
|
|
||||||
|
if( mCurrentCallEvent != null )
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentCallEvent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,22 +271,16 @@ public class P25DecoderState extends DecoderState
|
|||||||
processLDU( (LDUMessage)message );
|
processLDU( (LDUMessage)message );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terminator Data Unit with Link Control Message */
|
|
||||||
else if( message instanceof TDULinkControlMessage )
|
|
||||||
{
|
|
||||||
processTDULC( (TDULinkControlMessage)message );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trunking Signalling Messages */
|
/* Trunking Signalling Messages */
|
||||||
else if( message instanceof TSBKMessage )
|
else if( message instanceof TSBKMessage )
|
||||||
{
|
{
|
||||||
processTSBK( (TSBKMessage)message );
|
processTSBK( (TSBKMessage)message );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Header Data Unit Message - preceeds voice LDUs */
|
/* Terminator Data Unit with Link Control Message */
|
||||||
else if( message instanceof HDUMessage )
|
else if( message instanceof TDULinkControlMessage )
|
||||||
{
|
{
|
||||||
processHDU( (HDUMessage)message );
|
processTDULC( (TDULinkControlMessage)message );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Packet Data Unit Messages */
|
/* Packet Data Unit Messages */
|
||||||
@@ -272,6 +289,12 @@ public class P25DecoderState extends DecoderState
|
|||||||
processPDU( (PDUMessage)message );
|
processPDU( (PDUMessage)message );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header Data Unit Message - preceeds voice LDUs */
|
||||||
|
else if( message instanceof HDUMessage )
|
||||||
|
{
|
||||||
|
processHDU( (HDUMessage)message );
|
||||||
|
}
|
||||||
|
|
||||||
/* Terminator Data Unit, or default message if CRC failed */
|
/* Terminator Data Unit, or default message if CRC failed */
|
||||||
else if( message instanceof TDUMessage )
|
else if( message instanceof TDUMessage )
|
||||||
{
|
{
|
||||||
@@ -286,7 +309,10 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void processTDU( TDUMessage tdu )
|
private void processTDU( TDUMessage tdu )
|
||||||
{
|
{
|
||||||
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
|
// if( mCurrentCallEvent == null )
|
||||||
|
// {
|
||||||
|
// broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CONTROL ) );
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,56 +322,49 @@ public class P25DecoderState extends DecoderState
|
|||||||
{
|
{
|
||||||
if( hdu.isValid() )
|
if( hdu.isValid() )
|
||||||
{
|
{
|
||||||
State state = State.CALL;
|
State state = hdu.isEncrypted() ? State.ENCRYPTED : State.CALL;
|
||||||
|
|
||||||
if( hdu.isEncrypted() )
|
|
||||||
{
|
|
||||||
state = State.ENCRYPTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
broadcast( new DecoderStateEvent( this, Event.START, state ) );
|
broadcast( new DecoderStateEvent( this, Event.START, state ) );
|
||||||
|
|
||||||
updateTo( hdu.getToID() );
|
String to = hdu.getToID();
|
||||||
|
|
||||||
if( mChannelType == ChannelType.STANDARD )
|
if( mCurrentCallEvent == null )
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.CALL )
|
||||||
|
|
||||||
CallEventType type = CallEventType.CALL;
|
|
||||||
|
|
||||||
if( hdu.isEncrypted() )
|
|
||||||
{
|
|
||||||
type = CallEventType.ENCRYPTED_CALL;
|
|
||||||
|
|
||||||
sb.append( "ENCRYPTED WITH " );
|
|
||||||
sb.append( hdu.getEncryption().name() );
|
|
||||||
sb.append( " KEY:" );
|
|
||||||
sb.append( hdu.getKeyID() );
|
|
||||||
}
|
|
||||||
|
|
||||||
P25CallEvent event = new P25CallEvent.Builder( type )
|
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( mCurrentChannel )
|
.channel( mCurrentChannel )
|
||||||
.details( "Trigger:HDU" )
|
.details( ( hdu.isEncrypted() ? "ENCRYPTED " : "" ) )
|
||||||
.frequency( mCurrentChannelFrequency )
|
.frequency( mCurrentChannelFrequency )
|
||||||
.to( hdu.getToID() )
|
.to( to )
|
||||||
.details( sb.toString() )
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
mCurrentCallEvent = event;
|
broadcast( mCurrentCallEvent );
|
||||||
|
|
||||||
broadcast( event );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTo( to );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminator Data Unit with Link Control - indicates an end of the call
|
* Terminator Data Unit with Link Control - transmitted multiple times at
|
||||||
* sequences with embedded link control messages
|
* beginning or end of call sequence and includes embedded link control messages
|
||||||
*/
|
*/
|
||||||
private void processTDULC( TDULinkControlMessage tdulc )
|
private void processTDULC( TDULinkControlMessage tdulc )
|
||||||
{
|
{
|
||||||
broadcast( new DecoderStateEvent( this, Event.END, State.END ) );
|
if( tdulc.getOpcode() == LinkControlOpcode.CALL_TERMINATION_OR_CANCELLATION )
|
||||||
|
{
|
||||||
|
broadcast( new DecoderStateEvent( this, Event.END, State.END ) );
|
||||||
|
|
||||||
|
if( mCurrentCallEvent != null )
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.end();
|
||||||
|
mCurrentCallEvent = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, State.CALL ) );
|
||||||
|
}
|
||||||
|
|
||||||
switch( tdulc.getOpcode() )
|
switch( tdulc.getOpcode() )
|
||||||
{
|
{
|
||||||
@@ -384,6 +403,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CALL_TERMINATION_OR_CANCELLATION:
|
case CALL_TERMINATION_OR_CANCELLATION:
|
||||||
|
/* This opcode as handled at the beginning of the method */
|
||||||
break;
|
break;
|
||||||
case CHANNEL_IDENTIFIER_UPDATE:
|
case CHANNEL_IDENTIFIER_UPDATE:
|
||||||
//TODO: does the activity summary need this message?
|
//TODO: does the activity summary need this message?
|
||||||
@@ -434,20 +454,42 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GROUP_VOICE_CHANNEL_UPDATE:
|
case GROUP_VOICE_CHANNEL_UPDATE:
|
||||||
/* Reflects other call activity on the system: CALL DETECT */
|
/* Used only on trunked systems on the outbound channel, to
|
||||||
if( mChannelType == ChannelType.STANDARD &&
|
* reflect user activity on other channels. We process this
|
||||||
tdulc instanceof GroupVoiceChannelUpdate )
|
* as a call detect */
|
||||||
|
if( tdulc instanceof GroupVoiceChannelUpdate )
|
||||||
{
|
{
|
||||||
GroupVoiceChannelUpdate gvcu = (GroupVoiceChannelUpdate)tdulc;
|
GroupVoiceChannelUpdate gvcu = (GroupVoiceChannelUpdate)tdulc;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String groupA = gvcu.getGroupAddressA();
|
||||||
.aliasList( getAliasList() )
|
|
||||||
.channel( gvcu.getChannelA() )
|
if( !mCallDetectTalkgroups.contains( groupA ) )
|
||||||
.details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
|
{
|
||||||
.frequency( gvcu.getDownlinkFrequencyA() )
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
.from( gvcu.getGroupAddressA() )
|
.aliasList( getAliasList() )
|
||||||
.to( gvcu.getGroupAddressB() )
|
.channel( gvcu.getChannelA() )
|
||||||
.build() );
|
.details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
|
||||||
|
.frequency( gvcu.getDownlinkFrequencyA() )
|
||||||
|
.to( groupA )
|
||||||
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( groupA );
|
||||||
|
}
|
||||||
|
|
||||||
|
String groupB = gvcu.getGroupAddressB();
|
||||||
|
|
||||||
|
if( !mCallDetectTalkgroups.contains( groupB ) )
|
||||||
|
{
|
||||||
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
|
.aliasList( getAliasList() )
|
||||||
|
.channel( gvcu.getChannelB() )
|
||||||
|
.details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
|
||||||
|
.frequency( gvcu.getDownlinkFrequencyB() )
|
||||||
|
.to( groupB )
|
||||||
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( groupB );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
|
case GROUP_VOICE_CHANNEL_UPDATE_EXPLICIT:
|
||||||
@@ -458,31 +500,52 @@ public class P25DecoderState extends DecoderState
|
|||||||
GroupVoiceChannelUpdateExplicit gvcue =
|
GroupVoiceChannelUpdateExplicit gvcue =
|
||||||
(GroupVoiceChannelUpdateExplicit)tdulc;
|
(GroupVoiceChannelUpdateExplicit)tdulc;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String group = gvcue.getGroupAddress();
|
||||||
.aliasList( getAliasList() )
|
|
||||||
.channel( gvcue.getTransmitChannel() )
|
if( !mCallDetectTalkgroups.contains( group ) )
|
||||||
.details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
|
{
|
||||||
.frequency( gvcue.getDownlinkFrequency() )
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
.to( gvcue.getGroupAddress() )
|
.aliasList( getAliasList() )
|
||||||
.build() );
|
.channel( gvcue.getTransmitChannel() )
|
||||||
|
.details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
|
||||||
|
.frequency( gvcue.getDownlinkFrequency() )
|
||||||
|
.to( group )
|
||||||
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( group );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GROUP_VOICE_CHANNEL_USER:
|
case GROUP_VOICE_CHANNEL_USER:
|
||||||
if( mChannelType == ChannelType.STANDARD &&
|
/* Used on a traffic channel to reflect current call entities */
|
||||||
tdulc instanceof module.decode.p25.message.tdu.lc.GroupVoiceChannelUser )
|
if( tdulc instanceof module.decode.p25.message.tdu.lc.GroupVoiceChannelUser )
|
||||||
{
|
{
|
||||||
module.decode.p25.message.tdu.lc.GroupVoiceChannelUser gvcuser =
|
module.decode.p25.message.tdu.lc.GroupVoiceChannelUser gvcuser =
|
||||||
(module.decode.p25.message.tdu.lc.GroupVoiceChannelUser)tdulc;
|
(module.decode.p25.message.tdu.lc.GroupVoiceChannelUser)tdulc;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
broadcast( new DecoderStateEvent( this, Event.CONTINUATION,
|
||||||
.aliasList( getAliasList() )
|
( gvcuser.isEncrypted() ? State.ENCRYPTED : State.CALL ) ) );
|
||||||
.channel( mCurrentChannel )
|
|
||||||
.details( ( gvcuser.isEncrypted() ? "ENCRYPTED" : "" ) +
|
String from = gvcuser.getSourceAddress();
|
||||||
( gvcuser.isEmergency() ? " EMERGENCY" : "") )
|
String to = gvcuser.getGroupAddress();
|
||||||
.frequency( mCurrentChannelFrequency )
|
|
||||||
.from( gvcuser.getSourceAddress() )
|
if( mCurrentCallEvent == null )
|
||||||
.to( gvcuser.getGroupAddress() )
|
{
|
||||||
.build() );
|
mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
|
||||||
|
.aliasList( getAliasList() )
|
||||||
|
.channel( mCurrentChannel )
|
||||||
|
.details( ( gvcuser.isEncrypted() ? "ENCRYPTED " : "" ) +
|
||||||
|
( gvcuser.isEmergency() ? "EMERGENCY " : "") )
|
||||||
|
.frequency( mCurrentChannelFrequency )
|
||||||
|
.from( from )
|
||||||
|
.to( to )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFrom( from );
|
||||||
|
updateTo( to );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MESSAGE_UPDATE:
|
case MESSAGE_UPDATE:
|
||||||
@@ -687,16 +750,23 @@ public class P25DecoderState extends DecoderState
|
|||||||
module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser tivcu =
|
module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser tivcu =
|
||||||
(module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser)tdulc;
|
(module.decode.p25.message.tdu.lc.TelephoneInterconnectVoiceChannelUser)tdulc;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String to = tivcu.getAddress();
|
||||||
.aliasList( getAliasList() )
|
|
||||||
.channel( mCurrentChannel )
|
if( mCurrentCallEvent == null )
|
||||||
.details( "TELEPHONE INTERCONNECT " +
|
{
|
||||||
( tivcu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT )
|
||||||
( tivcu.isEmergency() ? " EMERGENCY" : "") )
|
.aliasList( getAliasList() )
|
||||||
.frequency( mCurrentChannelFrequency )
|
.channel( mCurrentChannel )
|
||||||
.from( null )
|
.details( ( tivcu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
||||||
.to( tivcu.getAddress() )
|
( tivcu.isEmergency() ? " EMERGENCY" : "") )
|
||||||
.build() );
|
.frequency( mCurrentChannelFrequency )
|
||||||
|
.to( to )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTo( to );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UNIT_AUTHENTICATION_COMMAND:
|
case UNIT_AUTHENTICATION_COMMAND:
|
||||||
@@ -752,21 +822,30 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
|
case UNIT_TO_UNIT_VOICE_CHANNEL_USER:
|
||||||
if( mChannelType == ChannelType.STANDARD &&
|
/* Used on traffic channels to indicate the current call entities */
|
||||||
tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser )
|
if( tdulc instanceof module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser )
|
||||||
{
|
{
|
||||||
module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser uuvcu =
|
module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser uuvcu =
|
||||||
(module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser)tdulc;
|
(module.decode.p25.message.tdu.lc.UnitToUnitVoiceChannelUser)tdulc;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String from = uuvcu.getSourceAddress();
|
||||||
.aliasList( getAliasList() )
|
String to = uuvcu.getTargetAddress();
|
||||||
.channel( mCurrentChannel )
|
|
||||||
.details( ( uuvcu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
if( mCurrentCallEvent != null )
|
||||||
( uuvcu.isEmergency() ? " EMERGENCY" : "" ) )
|
{
|
||||||
.frequency( mCurrentChannelFrequency )
|
mCurrentCallEvent = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
|
||||||
.from( uuvcu.getSourceAddress() )
|
.aliasList( getAliasList() )
|
||||||
.to( uuvcu.getTargetAddress() )
|
.channel( mCurrentChannel )
|
||||||
.build() );
|
.details( ( uuvcu.isEncrypted() ? "ENCRYPTED " : "" ) +
|
||||||
|
( uuvcu.isEmergency() ? "EMERGENCY " : "" ) )
|
||||||
|
.frequency( mCurrentChannelFrequency )
|
||||||
|
.from( from )
|
||||||
|
.to( to )
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFrom( from );
|
||||||
|
updateTo( to );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -780,36 +859,41 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void logAlternateVendorMessage( P25Message p25 )
|
private void logAlternateVendorMessage( P25Message p25 )
|
||||||
{
|
{
|
||||||
if( p25 instanceof TDULinkControlMessage )
|
// if( p25 instanceof TDULinkControlMessage )
|
||||||
{
|
// {
|
||||||
TDULinkControlMessage tdulc = (TDULinkControlMessage)p25;
|
// TDULinkControlMessage tdulc = (TDULinkControlMessage)p25;
|
||||||
|
//
|
||||||
mLog.debug( "TDULC - VENDOR [" + tdulc.getVendor() +
|
// mLog.debug( "TDULC - VENDOR [" + tdulc.getVendor() +
|
||||||
"] SPECIFIC FORMAT FOR " + tdulc.getVendorOpcode().getLabel() +
|
// "] SPECIFIC FORMAT FOR " + tdulc.getVendorOpcode().getLabel() +
|
||||||
" " + tdulc.getBinaryMessage() );
|
// " " + tdulc.getBinaryMessage() );
|
||||||
}
|
// }
|
||||||
else if( p25 instanceof LDU1Message )
|
// else if( p25 instanceof LDU1Message )
|
||||||
{
|
// {
|
||||||
LDU1Message ldu1 = (LDU1Message)p25;
|
// LDU1Message ldu1 = (LDU1Message)p25;
|
||||||
|
//
|
||||||
mLog.debug( "LDU1 - VENDOR [" + ldu1.getVendor() +
|
// mLog.debug( "LDU1 - VENDOR [" + ldu1.getVendor() +
|
||||||
"] SPECIFIC FORMAT FOR " + ldu1.getVendorOpcode().getLabel() +
|
// "] SPECIFIC FORMAT FOR " + ldu1.getVendorOpcode().getLabel() +
|
||||||
" " + ldu1.getBinaryMessage() );
|
// " " + ldu1.getBinaryMessage() );
|
||||||
}
|
// }
|
||||||
else if( p25 instanceof PDUMessage )
|
// else if( p25 instanceof PDUMessage )
|
||||||
{
|
// {
|
||||||
PDUMessage pdu = (PDUMessage)p25;
|
// PDUMessage pdu = (PDUMessage)p25;
|
||||||
|
//
|
||||||
mLog.debug( "PDU - VENDOR [" + pdu.getVendor() +
|
// mLog.debug( "PDU - VENDOR [" + pdu.getVendor() +
|
||||||
"] SPECIFIC FORMAT FOR " + pdu.getVendorOpcode().getLabel() +
|
// "] SPECIFIC FORMAT FOR " + pdu.getVendorOpcode().getLabel() +
|
||||||
" " + pdu.getBinaryMessage() );
|
// " " + pdu.getBinaryMessage() );
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
mLog.debug( "P25 - ALTERNATE VENDOR MESSAGE [" + p25.getClass() + "]" );
|
// mLog.debug( "P25 - ALTERNATE VENDOR MESSAGE [" + p25.getClass() + "]" );
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes LDU voice frame messages. Sends continuation events to keep
|
||||||
|
* the channel state synchronized and processes the embedded link control
|
||||||
|
* messages to capture/broadcast peripheral events like paging.
|
||||||
|
*/
|
||||||
private void processLDU( LDUMessage ldu )
|
private void processLDU( LDUMessage ldu )
|
||||||
{
|
{
|
||||||
State state = ( ldu.isValid() && ldu.isEncrypted() ) ?
|
State state = ( ldu.isValid() && ldu.isEncrypted() ) ?
|
||||||
@@ -817,6 +901,18 @@ public class P25DecoderState extends DecoderState
|
|||||||
|
|
||||||
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, state ) );
|
broadcast( new DecoderStateEvent( this, Event.CONTINUATION, state ) );
|
||||||
|
|
||||||
|
if( mCurrentCallEvent == null )
|
||||||
|
{
|
||||||
|
mCurrentCallEvent = new P25CallEvent.Builder(
|
||||||
|
( state == State.CALL ) ? CallEventType.CALL : CallEventType.ENCRYPTED_CALL )
|
||||||
|
.aliasList( getAliasList() )
|
||||||
|
.channel( mCurrentChannel )
|
||||||
|
.frequency( mCurrentChannelFrequency )
|
||||||
|
.build();
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
if( ldu instanceof LDU1Message )
|
if( ldu instanceof LDU1Message )
|
||||||
{
|
{
|
||||||
switch( ((LDU1Message)ldu).getOpcode() )
|
switch( ((LDU1Message)ldu).getOpcode() )
|
||||||
@@ -920,17 +1016,26 @@ public class P25DecoderState extends DecoderState
|
|||||||
module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate gvcu =
|
module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate gvcu =
|
||||||
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate)ldu;
|
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdate)ldu;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String userA = gvcu.getGroupAddressA();
|
||||||
|
|
||||||
|
if( !mCallDetectTalkgroups.contains( userA ) )
|
||||||
|
{
|
||||||
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcu.getChannelA() )
|
.channel( gvcu.getChannelA() )
|
||||||
.details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
|
.details( ( gvcu.isEncrypted() ? "ENCRYPTED" : "" ) )
|
||||||
.frequency( gvcu.getDownlinkFrequencyA() )
|
.frequency( gvcu.getDownlinkFrequencyA() )
|
||||||
.to( gvcu.getGroupAddressA() )
|
.to( userA )
|
||||||
.build() );
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( userA );
|
||||||
|
}
|
||||||
|
|
||||||
String userB = gvcu.getGroupAddressB();
|
String userB = gvcu.getGroupAddressB();
|
||||||
|
|
||||||
if( userB != null && !userB.contentEquals( "0000" ) )
|
if( userB != null &&
|
||||||
|
!userB.contentEquals( "0000" ) &&
|
||||||
|
!mCallDetectTalkgroups.contains( userB ) )
|
||||||
{
|
{
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
@@ -939,6 +1044,8 @@ public class P25DecoderState extends DecoderState
|
|||||||
.frequency( gvcu.getDownlinkFrequencyB() )
|
.frequency( gvcu.getDownlinkFrequencyB() )
|
||||||
.to( userB )
|
.to( userB )
|
||||||
.build() );
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( userB );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -953,13 +1060,20 @@ public class P25DecoderState extends DecoderState
|
|||||||
module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit gvcue =
|
module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit gvcue =
|
||||||
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit)ldu;
|
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUpdateExplicit)ldu;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
String group = gvcue.getGroupAddress();
|
||||||
|
|
||||||
|
if( !mCallDetectTalkgroups.contains( group ) )
|
||||||
|
{
|
||||||
|
broadcast( new P25CallEvent.Builder( CallEventType.CALL_DETECT )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcue.getTransmitChannel() )
|
.channel( gvcue.getTransmitChannel() )
|
||||||
.details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
|
.details( ( gvcue.isEncrypted() ? "ENCRYPTED" : "" ) )
|
||||||
.frequency( gvcue.getDownlinkFrequency() )
|
.frequency( gvcue.getDownlinkFrequency() )
|
||||||
.to( gvcue.getGroupAddress() )
|
.to( group )
|
||||||
.build() );
|
.build() );
|
||||||
|
|
||||||
|
mCallDetectTalkgroups.add( group );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -974,16 +1088,23 @@ public class P25DecoderState extends DecoderState
|
|||||||
module.decode.p25.message.ldu.lc.GroupVoiceChannelUser gvcuser =
|
module.decode.p25.message.ldu.lc.GroupVoiceChannelUser gvcuser =
|
||||||
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)ldu;
|
(module.decode.p25.message.ldu.lc.GroupVoiceChannelUser)ldu;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
if( mCurrentCallEvent.getCallEventType() != CallEventType.GROUP_CALL )
|
||||||
.aliasList( getAliasList() )
|
{
|
||||||
.channel( mCurrentChannel )
|
mCurrentCallEvent.setCallEventType( CallEventType.GROUP_CALL );
|
||||||
.details( "Trigger:LDU-GROUP_VOICE_CHANNEL_USER " +
|
broadcast( mCurrentCallEvent );
|
||||||
( gvcuser.isEncrypted() ? "ENCRYPTED" : "" ) +
|
}
|
||||||
( gvcuser.isEmergency() ? " EMERGENCY" : "") )
|
|
||||||
.frequency( mCurrentChannelFrequency )
|
if( mCurrentCallEvent.getDetails() == null )
|
||||||
.from( gvcuser.getSourceAddress() )
|
{
|
||||||
.to( gvcuser.getGroupAddress() )
|
mCurrentCallEvent.setDetails(
|
||||||
.build() );
|
( gvcuser.isEncrypted() ? "ENCRYPTED " : "" ) +
|
||||||
|
( gvcuser.isEmergency() ? "EMERGENCY " : "" ) );
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFrom( gvcuser.getSourceAddress() );
|
||||||
|
updateTo( gvcuser.getGroupAddress() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1179,17 +1300,22 @@ public class P25DecoderState extends DecoderState
|
|||||||
TelephoneInterconnectVoiceChannelUser tivcu =
|
TelephoneInterconnectVoiceChannelUser tivcu =
|
||||||
(TelephoneInterconnectVoiceChannelUser)ldu;
|
(TelephoneInterconnectVoiceChannelUser)ldu;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
if( mCurrentCallEvent.getCallEventType() != CallEventType.TELEPHONE_INTERCONNECT )
|
||||||
.aliasList( getAliasList() )
|
{
|
||||||
.channel( mCurrentChannel )
|
mCurrentCallEvent.setCallEventType( CallEventType.TELEPHONE_INTERCONNECT );
|
||||||
.details( "Trigger: LDU-TEL_INT_VOIC_CHAN_USER " +
|
broadcast( mCurrentCallEvent );
|
||||||
"TELEPHONE INTERCONNECT " +
|
}
|
||||||
( tivcu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
|
||||||
( tivcu.isEmergency() ? " EMERGENCY" : "") )
|
if( mCurrentCallEvent.getDetails() == null )
|
||||||
.frequency( mCurrentChannelFrequency )
|
{
|
||||||
.from( null )
|
mCurrentCallEvent.setDetails(
|
||||||
.to( tivcu.getAddress() )
|
( tivcu.isEncrypted() ? "ENCRYPTED " : "" ) +
|
||||||
.build() );
|
( tivcu.isEmergency() ? "EMERGENCY " : "" ) );
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTo( tivcu.getAddress() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1255,16 +1381,23 @@ public class P25DecoderState extends DecoderState
|
|||||||
UnitToUnitVoiceChannelUser uuvcu =
|
UnitToUnitVoiceChannelUser uuvcu =
|
||||||
(UnitToUnitVoiceChannelUser)ldu;
|
(UnitToUnitVoiceChannelUser)ldu;
|
||||||
|
|
||||||
broadcast( new P25CallEvent.Builder( CallEventType.CALL )
|
if( mCurrentCallEvent.getCallEventType() != CallEventType.UNIT_TO_UNIT_CALL )
|
||||||
.aliasList( getAliasList() )
|
{
|
||||||
.channel( mCurrentChannel )
|
mCurrentCallEvent.setCallEventType( CallEventType.UNIT_TO_UNIT_CALL );
|
||||||
.details( "Trigger:LDU-U2U_VOICE_CHAN_USER " +
|
broadcast( mCurrentCallEvent );
|
||||||
( uuvcu.isEncrypted() ? "ENCRYPTED" : "" ) +
|
}
|
||||||
( uuvcu.isEmergency() ? " EMERGENCY" : "" ) )
|
|
||||||
.frequency( mCurrentChannelFrequency )
|
if( mCurrentCallEvent.getDetails() == null )
|
||||||
.from( uuvcu.getSourceAddress() )
|
{
|
||||||
.to( uuvcu.getTargetAddress() )
|
mCurrentCallEvent.setDetails(
|
||||||
.build() );
|
( uuvcu.isEncrypted() ? "ENCRYPTED " : "" ) +
|
||||||
|
( uuvcu.isEmergency() ? "EMERGENCY " : "" ) );
|
||||||
|
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
|
updateFrom( uuvcu.getSourceAddress() );
|
||||||
|
updateTo( uuvcu.getTargetAddress() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2366,7 +2499,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
case GROUP_VOICE_CHANNEL_GRANT:
|
case GROUP_VOICE_CHANNEL_GRANT:
|
||||||
GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)message;
|
GroupVoiceChannelGrant gvcg = (GroupVoiceChannelGrant)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.CALL )
|
event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcg.getChannel() )
|
.channel( gvcg.getChannel() )
|
||||||
.details( "Trigger: TSBK-G_V_CH_GRNT " +
|
.details( "Trigger: TSBK-G_V_CH_GRNT " +
|
||||||
@@ -2381,7 +2514,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
GroupVoiceChannelGrantUpdate gvcgu =
|
GroupVoiceChannelGrantUpdate gvcgu =
|
||||||
(GroupVoiceChannelGrantUpdate)message;
|
(GroupVoiceChannelGrantUpdate)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.CALL )
|
event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcgu.getChannel1() )
|
.channel( gvcgu.getChannel1() )
|
||||||
.details( "Trigger: TSBK-G_V_CH_GRNT_UP " +
|
.details( "Trigger: TSBK-G_V_CH_GRNT_UP " +
|
||||||
@@ -2394,7 +2527,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
if( gvcgu.hasChannelNumber2() )
|
if( gvcgu.hasChannelNumber2() )
|
||||||
{
|
{
|
||||||
/* We handle this channel grant independent of the first event */
|
/* We handle this channel grant independent of the first event */
|
||||||
P25CallEvent event2 = new P25CallEvent.Builder( CallEventType.CALL )
|
P25CallEvent event2 = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcgu.getChannel2() )
|
.channel( gvcgu.getChannel2() )
|
||||||
.details( "Trigger: TSBK-G_V_CH_GRNT_UP#2 " +
|
.details( "Trigger: TSBK-G_V_CH_GRNT_UP#2 " +
|
||||||
@@ -2411,7 +2544,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
GroupVoiceChannelGrantUpdateExplicit gvcgue =
|
GroupVoiceChannelGrantUpdateExplicit gvcgue =
|
||||||
(GroupVoiceChannelGrantUpdateExplicit)message;
|
(GroupVoiceChannelGrantUpdateExplicit)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.CALL )
|
event = new P25CallEvent.Builder( CallEventType.GROUP_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( gvcgue.getTransmitChannelIdentifier() + "-" +
|
.channel( gvcgue.getTransmitChannelIdentifier() + "-" +
|
||||||
gvcgue.getTransmitChannelNumber() )
|
gvcgue.getTransmitChannelNumber() )
|
||||||
@@ -2452,7 +2585,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
TelephoneInterconnectVoiceChannelGrant tivcg =
|
TelephoneInterconnectVoiceChannelGrant tivcg =
|
||||||
(TelephoneInterconnectVoiceChannelGrant)message;
|
(TelephoneInterconnectVoiceChannelGrant)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.TELEPHONE_CALL )
|
event = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( tivcg.getChannel() )
|
.channel( tivcg.getChannel() )
|
||||||
.details( "Trigger: TSBK-T_INT_V_CH_GRNT " +
|
.details( "Trigger: TSBK-T_INT_V_CH_GRNT " +
|
||||||
@@ -2467,7 +2600,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
TelephoneInterconnectVoiceChannelGrantUpdate tivcgu =
|
TelephoneInterconnectVoiceChannelGrantUpdate tivcgu =
|
||||||
(TelephoneInterconnectVoiceChannelGrantUpdate)message;
|
(TelephoneInterconnectVoiceChannelGrantUpdate)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.TELEPHONE_CALL )
|
event = new P25CallEvent.Builder( CallEventType.TELEPHONE_INTERCONNECT )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( tivcgu.getChannelIdentifier() + "-" +
|
.channel( tivcgu.getChannelIdentifier() + "-" +
|
||||||
tivcgu.getChannelNumber() )
|
tivcgu.getChannelNumber() )
|
||||||
@@ -2482,7 +2615,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
UnitToUnitVoiceChannelGrant uuvcg =
|
UnitToUnitVoiceChannelGrant uuvcg =
|
||||||
(UnitToUnitVoiceChannelGrant)message;
|
(UnitToUnitVoiceChannelGrant)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.CALL )
|
event = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( uuvcg.getChannelIdentifier() + "-" +
|
.channel( uuvcg.getChannelIdentifier() + "-" +
|
||||||
uuvcg.getChannelNumber() )
|
uuvcg.getChannelNumber() )
|
||||||
@@ -2498,7 +2631,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
UnitToUnitVoiceChannelGrantUpdate uuvcgu =
|
UnitToUnitVoiceChannelGrantUpdate uuvcgu =
|
||||||
(UnitToUnitVoiceChannelGrantUpdate)message;
|
(UnitToUnitVoiceChannelGrantUpdate)message;
|
||||||
|
|
||||||
event = new P25CallEvent.Builder( CallEventType.CALL )
|
event = new P25CallEvent.Builder( CallEventType.UNIT_TO_UNIT_CALL )
|
||||||
.aliasList( getAliasList() )
|
.aliasList( getAliasList() )
|
||||||
.channel( uuvcgu.getChannelIdentifier() + "-" +
|
.channel( uuvcgu.getChannelIdentifier() + "-" +
|
||||||
uuvcgu.getChannelNumber() )
|
uuvcgu.getChannelNumber() )
|
||||||
@@ -2514,7 +2647,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( event != null )
|
if( event != null && event.getCallEventType() != CallEventType.DATA_CALL )
|
||||||
{
|
{
|
||||||
broadcast( new TrafficChannelAllocationEvent( this, event ) );
|
broadcast( new TrafficChannelAllocationEvent( this, event ) );
|
||||||
}
|
}
|
||||||
@@ -2525,6 +2658,7 @@ public class P25DecoderState extends DecoderState
|
|||||||
*/
|
*/
|
||||||
private void updateTo( String to )
|
private void updateTo( String to )
|
||||||
{
|
{
|
||||||
|
mLog.debug( "Updating to [" + to + "]" );
|
||||||
if( to != null &&
|
if( to != null &&
|
||||||
!to.contentEquals( "0000" ) &&
|
!to.contentEquals( "0000" ) &&
|
||||||
!to.contentEquals( "000000" ) &&
|
!to.contentEquals( "000000" ) &&
|
||||||
@@ -2533,16 +2667,29 @@ public class P25DecoderState extends DecoderState
|
|||||||
mToTalkgroup = to;
|
mToTalkgroup = to;
|
||||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||||
|
|
||||||
|
if( mCurrentCallEvent != null &&
|
||||||
|
( mCurrentCallEvent.getToID() == null ||
|
||||||
|
!mCurrentCallEvent.getToID().contentEquals( to ) ) )
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.setToID( to );
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
if( hasAliasList() )
|
if( hasAliasList() )
|
||||||
{
|
{
|
||||||
mToAlias = getAliasList().getTalkgroupAlias( to );
|
mToAlias = getAliasList().getTalkgroupAlias( mToTalkgroup );
|
||||||
|
mLog.debug( "To Alias: " + mToAlias );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
mLog.debug( "To Alias: no alias list" );
|
||||||
mToAlias = null;
|
mToAlias = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||||
|
|
||||||
|
/* Send audio metadata update */
|
||||||
|
broadcast( new Metadata( MetadataType.TO, to, mToAlias, true ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2557,12 +2704,19 @@ public class P25DecoderState extends DecoderState
|
|||||||
( mFromTalkgroup == null || !mFromTalkgroup.contentEquals( from ) ) )
|
( mFromTalkgroup == null || !mFromTalkgroup.contentEquals( from ) ) )
|
||||||
{
|
{
|
||||||
mFromTalkgroup = from;
|
mFromTalkgroup = from;
|
||||||
|
|
||||||
broadcast( ChangedAttribute.FROM_TALKGROUP );
|
broadcast( ChangedAttribute.FROM_TALKGROUP );
|
||||||
|
|
||||||
|
if( mCurrentCallEvent != null &&
|
||||||
|
mCurrentCallEvent.getFromID() == null ||
|
||||||
|
!mCurrentCallEvent.getFromID().contentEquals( from ) )
|
||||||
|
{
|
||||||
|
mCurrentCallEvent.setFromID( from );
|
||||||
|
broadcast( mCurrentCallEvent );
|
||||||
|
}
|
||||||
|
|
||||||
if( hasAliasList() )
|
if( hasAliasList() )
|
||||||
{
|
{
|
||||||
mFromAlias = getAliasList().getTalkgroupAlias( from );
|
mFromAlias = getAliasList().getTalkgroupAlias( mFromTalkgroup );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2570,6 +2724,9 @@ public class P25DecoderState extends DecoderState
|
|||||||
}
|
}
|
||||||
|
|
||||||
broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
|
broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
|
||||||
|
|
||||||
|
/* Send audio metadata update */
|
||||||
|
broadcast( new Metadata( MetadataType.FROM, from, mFromAlias, true ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2959,6 +3116,17 @@ public class P25DecoderState extends DecoderState
|
|||||||
|
|
||||||
mToTalkgroup = allocationEvent.getCallEvent().getToID();
|
mToTalkgroup = allocationEvent.getCallEvent().getToID();
|
||||||
broadcast( ChangedAttribute.TO_TALKGROUP );
|
broadcast( ChangedAttribute.TO_TALKGROUP );
|
||||||
|
|
||||||
|
if( allocationEvent.getCallEvent().hasAliasList() )
|
||||||
|
{
|
||||||
|
AliasList aliasList = allocationEvent.getCallEvent().getAliasList();
|
||||||
|
|
||||||
|
mFromAlias = aliasList.getTalkgroupAlias( mFromTalkgroup );
|
||||||
|
broadcast( ChangedAttribute.FROM_TALKGROUP_ALIAS );
|
||||||
|
|
||||||
|
mToAlias = aliasList.getTalkgroupAlias( mToTalkgroup );
|
||||||
|
broadcast( ChangedAttribute.TO_TALKGROUP_ALIAS );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -17,12 +17,12 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package module.decode.p25;
|
package module.decode.p25;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
import javax.swing.DefaultComboBoxModel;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JSlider;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
import module.decode.DecodeEditor;
|
import module.decode.DecodeEditor;
|
||||||
import module.decode.config.DecodeConfiguration;
|
import module.decode.config.DecodeConfiguration;
|
||||||
@@ -43,6 +43,10 @@ public class P25Editor extends DecodeEditor
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private JComboBox<P25_LSMDecoder.Modulation> mComboModulation;
|
private JComboBox<P25_LSMDecoder.Modulation> mComboModulation;
|
||||||
|
private JLabel mCallTimeoutLabel;
|
||||||
|
private JSlider mCallTimeout;
|
||||||
|
private JLabel mTrafficChannelPoolSizeLabel;
|
||||||
|
private JSlider mTrafficChannelPoolSize;
|
||||||
|
|
||||||
public P25Editor( DecodeConfiguration config )
|
public P25Editor( DecodeConfiguration config )
|
||||||
{
|
{
|
||||||
@@ -60,23 +64,62 @@ public class P25Editor extends DecodeEditor
|
|||||||
|
|
||||||
mComboModulation.setSelectedItem( ((DecodeConfigP25Phase1)mConfig).getModulation() );
|
mComboModulation.setSelectedItem( ((DecodeConfigP25Phase1)mConfig).getModulation() );
|
||||||
|
|
||||||
mComboModulation.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
P25_LSMDecoder.Modulation selected = mComboModulation
|
|
||||||
.getItemAt( mComboModulation.getSelectedIndex() );
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
((DecodeConfigP25Phase1)mConfig).setModulation( selected );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( new JLabel( "Modulation:" ) );
|
add( new JLabel( "Modulation:" ) );
|
||||||
add( mComboModulation, "wrap" );
|
add( mComboModulation, "wrap" );
|
||||||
|
|
||||||
|
mCallTimeout = new JSlider( JSlider.HORIZONTAL,
|
||||||
|
DecodeConfiguration.CALL_TIMEOUT_MINIMUM,
|
||||||
|
DecodeConfiguration.CALL_TIMEOUT_MAXIMUM,
|
||||||
|
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS );
|
||||||
|
|
||||||
|
mCallTimeout.setMajorTickSpacing( 90 );
|
||||||
|
mCallTimeout.setMinorTickSpacing( 10 );
|
||||||
|
mCallTimeout.setPaintTicks( true );
|
||||||
|
|
||||||
|
mCallTimeout.setLabelTable( mCallTimeout.createStandardLabels( 100, 100 ) );
|
||||||
|
mCallTimeout.setPaintLabels( true );
|
||||||
|
|
||||||
|
mCallTimeoutLabel = new JLabel( "Call Timeout: " + mCallTimeout.getValue() + " " );
|
||||||
|
|
||||||
|
mCallTimeout.addChangeListener( new ChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void stateChanged( ChangeEvent e )
|
||||||
|
{
|
||||||
|
mCallTimeoutLabel.setText( "Call Timeout: " + mCallTimeout.getValue() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
add( mCallTimeoutLabel );
|
||||||
|
add( mCallTimeout, "wrap,grow" );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSize = new JSlider( JSlider.HORIZONTAL,
|
||||||
|
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MINIMUM,
|
||||||
|
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_MAXIMUM,
|
||||||
|
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSize.setMajorTickSpacing( 10 );
|
||||||
|
mTrafficChannelPoolSize.setMinorTickSpacing( 1 );
|
||||||
|
mTrafficChannelPoolSize.setPaintTicks( true );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSize.setLabelTable( mTrafficChannelPoolSize.createStandardLabels( 10, 10 ) );
|
||||||
|
mTrafficChannelPoolSize.setPaintLabels( true );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSizeLabel = new JLabel( "Traffic Channel Pool Size: " + mTrafficChannelPoolSize.getValue() + " " );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSize.addChangeListener( new ChangeListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void stateChanged( ChangeEvent e )
|
||||||
|
{
|
||||||
|
mTrafficChannelPoolSizeLabel.setText( "Traffic Channel Pool Size: " + mTrafficChannelPoolSize.getValue() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
add( mTrafficChannelPoolSizeLabel );
|
||||||
|
add( mTrafficChannelPoolSize, "wrap,grow" );
|
||||||
|
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,4 +142,28 @@ public class P25Editor extends DecodeEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save()
|
||||||
|
{
|
||||||
|
DecodeConfigP25Phase1 config = (DecodeConfigP25Phase1)mConfig;
|
||||||
|
|
||||||
|
config.setModulation( (Modulation)mComboModulation.getSelectedItem() );
|
||||||
|
|
||||||
|
config.setCallTimeout( mCallTimeout.getValue() );
|
||||||
|
|
||||||
|
config.setTrafficChannelPoolSize( mTrafficChannelPoolSize.getValue() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset()
|
||||||
|
{
|
||||||
|
DecodeConfigP25Phase1 config = (DecodeConfigP25Phase1)mConfig;
|
||||||
|
|
||||||
|
mComboModulation.setSelectedItem( config.getModulation() );
|
||||||
|
|
||||||
|
mCallTimeout.setValue( config.getCallTimeout() );
|
||||||
|
|
||||||
|
mTrafficChannelPoolSize.setValue( config.getTrafficChannelPoolSize() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import module.decode.p25.message.tdu.lc.TDULinkControlMessage;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import controller.channel.ChannelEvent;
|
|
||||||
import controller.channel.IChannelEventListener;
|
|
||||||
import sample.Listener;
|
import sample.Listener;
|
||||||
import audio.AudioFormats;
|
import audio.AudioFormats;
|
||||||
import audio.AudioPacket;
|
import audio.AudioPacket;
|
||||||
@@ -21,9 +19,14 @@ import audio.IAudioPacketProvider;
|
|||||||
import audio.metadata.AudioMetadata;
|
import audio.metadata.AudioMetadata;
|
||||||
import audio.metadata.IMetadataListener;
|
import audio.metadata.IMetadataListener;
|
||||||
import audio.metadata.Metadata;
|
import audio.metadata.Metadata;
|
||||||
|
import audio.squelch.ISquelchStateListener;
|
||||||
|
import audio.squelch.SquelchState;
|
||||||
|
import controller.channel.ChannelEvent;
|
||||||
|
import controller.channel.IChannelEventListener;
|
||||||
|
|
||||||
public class P25AudioModule extends Module implements Listener<Message>,
|
public class P25AudioModule extends Module implements Listener<Message>,
|
||||||
IAudioPacketProvider, IMessageListener, IChannelEventListener, IMetadataListener
|
IAudioPacketProvider, IMessageListener, IChannelEventListener,
|
||||||
|
IMetadataListener, ISquelchStateListener
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( P25AudioModule.class );
|
private final static Logger mLog = LoggerFactory.getLogger( P25AudioModule.class );
|
||||||
|
|
||||||
@@ -40,6 +43,7 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
|||||||
private Listener<AudioPacket> mAudioPacketListener;
|
private Listener<AudioPacket> mAudioPacketListener;
|
||||||
private AudioMetadata mAudioMetadata;
|
private AudioMetadata mAudioMetadata;
|
||||||
private ChannelEventListener mChannelEventListener = new ChannelEventListener();
|
private ChannelEventListener mChannelEventListener = new ChannelEventListener();
|
||||||
|
private SquelchStateListener mSquelchStateListener = new SquelchStateListener();
|
||||||
|
|
||||||
public P25AudioModule( boolean record )
|
public P25AudioModule( boolean record )
|
||||||
{
|
{
|
||||||
@@ -55,6 +59,12 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Listener<SquelchState> getSquelchStateListener()
|
||||||
|
{
|
||||||
|
return mSquelchStateListener;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose()
|
public void dispose()
|
||||||
{
|
{
|
||||||
@@ -134,8 +144,10 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
|||||||
|
|
||||||
library = (AudioConversionLibrary)temp.newInstance();
|
library = (AudioConversionLibrary)temp.newInstance();
|
||||||
|
|
||||||
if( ( library.getMajorVersion() == 0 && library.getMinorVersion() >= 3 ) ||
|
if( ( library.getMajorVersion() == 0 &&
|
||||||
library.getMajorVersion() >= 1 )
|
library.getMinorVersion() >= 3 &&
|
||||||
|
library.getBuildVersion() >= 1 ) ||
|
||||||
|
library.getMajorVersion() >= 1 )
|
||||||
{
|
{
|
||||||
mAudioConverter = library.getAudioConverter( IMBE_CODEC,
|
mAudioConverter = library.getAudioConverter( IMBE_CODEC,
|
||||||
AudioFormats.PCM_SIGNED_48KHZ_16BITS_MONO );
|
AudioFormats.PCM_SIGNED_48KHZ_16BITS_MONO );
|
||||||
@@ -163,7 +175,7 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mLog.debug( "JMBE library version 0.3.x or higher is required" );
|
mLog.debug( "JMBE library version 0.3.1 or higher is required - found: " + library.getVersion() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( ClassNotFoundException e1 )
|
catch ( ClassNotFoundException e1 )
|
||||||
@@ -239,4 +251,25 @@ public class P25AudioModule extends Module implements Listener<Message>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for squelch state listener. Internally, the P25 audio module
|
||||||
|
* doesn't have a squelch state. If there are IMBE audio frames, we have
|
||||||
|
* audio. We use this listener to signal to the recorder manager that the
|
||||||
|
* channel state is resetting and it should end the recording.
|
||||||
|
*/
|
||||||
|
public class SquelchStateListener implements Listener<SquelchState>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void receive( SquelchState state )
|
||||||
|
{
|
||||||
|
if( state == SquelchState.SQUELCH && mAudioPacketListener != null )
|
||||||
|
{
|
||||||
|
mAudioPacketListener.receive( new AudioPacket( AudioPacket.Type.END,
|
||||||
|
mAudioMetadata.copyOf() ) );
|
||||||
|
|
||||||
|
mAudioMetadata.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,9 +163,11 @@ public class ChannelState extends Module implements ICallEventProvider,
|
|||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEndingState()
|
private boolean isIdleOrEndingState()
|
||||||
{
|
{
|
||||||
return mState == State.FADE || mState == State.END;
|
return mState == State.FADE ||
|
||||||
|
mState == State.END ||
|
||||||
|
mState == State.IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -568,7 +570,7 @@ public class ChannelState extends Module implements ICallEventProvider,
|
|||||||
mSquelchLocked = true;
|
mSquelchLocked = true;
|
||||||
break;
|
break;
|
||||||
case CONTINUATION:
|
case CONTINUATION:
|
||||||
if( isEndingState() )
|
if( isIdleOrEndingState() )
|
||||||
{
|
{
|
||||||
setState( event.getState() );
|
setState( event.getState() );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,37 +59,37 @@ public class RecorderManager implements Listener<AudioPacket>
|
|||||||
{
|
{
|
||||||
if( audioPacket.hasAudioMetadata() &&
|
if( audioPacket.hasAudioMetadata() &&
|
||||||
audioPacket.getAudioMetadata().isRecordable() )
|
audioPacket.getAudioMetadata().isRecordable() )
|
||||||
|
{
|
||||||
|
String identifier = audioPacket.getAudioMetadata().getIdentifier();
|
||||||
|
|
||||||
|
if( mRecorders.containsKey( identifier ) )
|
||||||
{
|
{
|
||||||
String identifier = audioPacket.getAudioMetadata().getIdentifier();
|
RealBufferWaveRecorder recorder = mRecorders.get( identifier );
|
||||||
|
|
||||||
if( mRecorders.containsKey( identifier ) )
|
if( audioPacket.getType() == AudioPacket.Type.AUDIO )
|
||||||
{
|
{
|
||||||
RealBufferWaveRecorder recorder = mRecorders.get( identifier );
|
|
||||||
|
|
||||||
if( audioPacket.getType() == AudioPacket.Type.AUDIO )
|
|
||||||
{
|
|
||||||
recorder.receive( audioPacket.getAudioBuffer() );
|
|
||||||
}
|
|
||||||
else if( audioPacket.getType() == AudioPacket.Type.END )
|
|
||||||
{
|
|
||||||
mRecorders.remove( identifier );
|
|
||||||
recorder.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( audioPacket.getType() == AudioPacket.Type.AUDIO )
|
|
||||||
{
|
|
||||||
String filePrefix = getFilePrefix( audioPacket );
|
|
||||||
|
|
||||||
RealBufferWaveRecorder recorder =
|
|
||||||
new RealBufferWaveRecorder( mThreadPoolManager,
|
|
||||||
AUDIO_SAMPLE_RATE, filePrefix );
|
|
||||||
|
|
||||||
recorder.start();
|
|
||||||
|
|
||||||
recorder.receive( audioPacket.getAudioBuffer() );
|
recorder.receive( audioPacket.getAudioBuffer() );
|
||||||
mRecorders.put( identifier, recorder );
|
}
|
||||||
|
else if( audioPacket.getType() == AudioPacket.Type.END )
|
||||||
|
{
|
||||||
|
mRecorders.remove( identifier );
|
||||||
|
recorder.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if( audioPacket.getType() == AudioPacket.Type.AUDIO )
|
||||||
|
{
|
||||||
|
String filePrefix = getFilePrefix( audioPacket );
|
||||||
|
|
||||||
|
RealBufferWaveRecorder recorder =
|
||||||
|
new RealBufferWaveRecorder( mThreadPoolManager,
|
||||||
|
AUDIO_SAMPLE_RATE, filePrefix );
|
||||||
|
|
||||||
|
recorder.start();
|
||||||
|
|
||||||
|
recorder.receive( audioPacket.getAudioBuffer() );
|
||||||
|
mRecorders.put( identifier, recorder );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user