diff --git a/src/main/java/io/github/dsheirer/audio/broadcast/broadcastify/BroadcastifyCallBroadcaster.java b/src/main/java/io/github/dsheirer/audio/broadcast/broadcastify/BroadcastifyCallBroadcaster.java index 276bb660..3ace0bba 100644 --- a/src/main/java/io/github/dsheirer/audio/broadcast/broadcastify/BroadcastifyCallBroadcaster.java +++ b/src/main/java/io/github/dsheirer/audio/broadcast/broadcastify/BroadcastifyCallBroadcaster.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2020 Dennis Sheirer + * Copyright (C) 2014-2022 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 @@ -417,38 +417,48 @@ public class BroadcastifyCallBroadcaster extends AbstractAudioBroadcaster toIdentifiers = audioRecording.getIdentifierCollection().getIdentifiers(Role.TO); - if(toIdentifiers.size() >= 1) + //Format a patch group first, if there are multiples + for(Identifier identifier: toIdentifiers) { - Identifier to = toIdentifiers.get(0); - - if(to instanceof TalkgroupIdentifier) + if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier) + { + return format(patchGroupIdentifier); + } + } + + for(Identifier identifier: toIdentifiers) + { + if(identifier instanceof TalkgroupIdentifier talkgroupIdentifier) { - TalkgroupIdentifier talkgroupIdentifier = (TalkgroupIdentifier)to; return String.valueOf(RadioReferenceDecoder.convertToRadioReferenceTalkgroup(talkgroupIdentifier.getValue(), - talkgroupIdentifier.getProtocol())); + talkgroupIdentifier.getProtocol())); } - else if(to instanceof PatchGroupIdentifier) + else if(identifier instanceof RadioIdentifier radioIdentifier) { - PatchGroup patchGroup = ((PatchGroupIdentifier)to).getValue(); - - StringBuilder sb = new StringBuilder(); - sb.append(patchGroup.getPatchGroup().getValue().toString()); - for(TalkgroupIdentifier patched: patchGroup.getPatchedGroupIdentifiers()) - { - sb.append(",").append(patched.getValue()); - } - - return sb.toString(); - } - else if(to instanceof RadioIdentifier) - { - return ((RadioIdentifier)to).getValue().toString(); + return radioIdentifier.getValue().toString(); } } return "0"; } + /** + * Formats a patch group + */ + public static String format(PatchGroupIdentifier patchGroupIdentifier) + { + PatchGroup patchGroup = patchGroupIdentifier.getValue(); + + StringBuilder sb = new StringBuilder(); + sb.append(patchGroup.getPatchGroup().getValue().toString()); + for(TalkgroupIdentifier patched: patchGroup.getPatchedGroupIdentifiers()) + { + sb.append(",").append(patched.getValue()); + } + + return sb.toString(); + } + /** * Tests both the connection and configuration against the Broadcastify Call API service * @param configuration containing API key and system id diff --git a/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupManager.java b/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupManager.java index cd8337a7..6b32c3fc 100644 --- a/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupManager.java +++ b/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupManager.java @@ -1,7 +1,6 @@ /* - * ****************************************************************************** - * sdrtrunk - * Copyright (C) 2014-2019 Dennis Sheirer + * ***************************************************************************** + * Copyright (C) 2014-2022 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 @@ -15,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see - * ***************************************************************************** + * **************************************************************************** */ package io.github.dsheirer.identifier.patch; @@ -46,10 +45,22 @@ public class PatchGroupManager private Map mPatchGroupLastUpdatedMap = new HashMap<>(); private Map mPatchGroupMap = new HashMap<>(); + /** + * Constructs an instance + */ public PatchGroupManager() { } + /** + * Clears any existing patch groups + */ + public void clear() + { + mPatchGroupMap.clear(); + mPatchGroupLastUpdatedMap.clear(); + } + /** * Adds the patch group identifier to the set of managed patch groups. If the patch group is already being * managed, the new identifier is checked for additional patched talkgroups and they are added to the existing diff --git a/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupPreLoadDataContent.java b/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupPreLoadDataContent.java new file mode 100644 index 00000000..2172fece --- /dev/null +++ b/src/main/java/io/github/dsheirer/identifier/patch/PatchGroupPreLoadDataContent.java @@ -0,0 +1,39 @@ +/* + * ***************************************************************************** + * Copyright (C) 2014-2022 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 + * **************************************************************************** + */ + +package io.github.dsheirer.identifier.patch; + +import io.github.dsheirer.controller.channel.event.PreloadDataContent; +import io.github.dsheirer.identifier.IdentifierCollection; + +/** + * Preload patch group data content carrying the current list of identifiers in an identifier collection. + */ +public class PatchGroupPreLoadDataContent extends PreloadDataContent +{ + /** + * Constructs an instance + * + * @param data to preload + */ + public PatchGroupPreLoadDataContent(IdentifierCollection data) + { + super(data); + } +} diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java index c6ba79bb..737c542c 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/P25TrafficChannelManager.java @@ -1,23 +1,20 @@ /* + * ***************************************************************************** + * Copyright (C) 2014-2022 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 - * * ***************************************************************************** + * 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 + * **************************************************************************** */ package io.github.dsheirer.module.decode.p25; @@ -32,6 +29,7 @@ import io.github.dsheirer.identifier.Identifier; import io.github.dsheirer.identifier.IdentifierCollection; import io.github.dsheirer.identifier.MutableIdentifierCollection; import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent; import io.github.dsheirer.identifier.scramble.ScrambleParameterIdentifier; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.message.IMessageListener; @@ -315,7 +313,11 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I sourceConfig.setFrequency(frequency); trafficChannel.setSourceConfiguration(sourceConfig); mAllocatedTrafficChannelMap.put(frequency, trafficChannel); - getInterModuleEventBus().post(new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection)); + + ChannelStartProcessingRequest startChannelRequest = + new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection); + startChannelRequest.addPreloadDataContent(new PatchGroupPreLoadDataContent(identifierCollection)); + getInterModuleEventBus().post(startChannelRequest); } } @@ -361,7 +363,11 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I sourceConfig.setFrequency(frequency); trafficChannel.setSourceConfiguration(sourceConfig); mAllocatedTrafficChannelMap.put(frequency, trafficChannel); - getInterModuleEventBus().post(new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection)); + + ChannelStartProcessingRequest startChannelRequest = + new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection); + startChannelRequest.addPreloadDataContent(new PatchGroupPreLoadDataContent(identifierCollection)); + getInterModuleEventBus().post(startChannelRequest); } broadcast(channelGrantEvent); @@ -465,7 +471,10 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I decodeConfig.setScrambleParameters(mPhase2ScrambleParameters.copy()); } - getInterModuleEventBus().post(new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection)); + ChannelStartProcessingRequest startChannelRequest = + new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection); + startChannelRequest.addPreloadDataContent(new PatchGroupPreLoadDataContent(identifierCollection)); + getInterModuleEventBus().post(startChannelRequest); } } @@ -519,7 +528,11 @@ public class P25TrafficChannelManager extends TrafficChannelManager implements I sourceConfig.setFrequency(frequency); trafficChannel.setSourceConfiguration(sourceConfig); mAllocatedTrafficChannelMap.put(frequency, trafficChannel); - getInterModuleEventBus().post(new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection)); + + ChannelStartProcessingRequest startChannelRequest = + new ChannelStartProcessingRequest(trafficChannel, apco25Channel, identifierCollection); + startChannelRequest.addPreloadDataContent(new PatchGroupPreLoadDataContent(identifierCollection)); + getInterModuleEventBus().post(startChannelRequest); } broadcast(channelGrantEvent); diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java index 2d57bf20..bcf50f27 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase1/P25P1DecoderState.java @@ -1,6 +1,6 @@ /* * ***************************************************************************** - * Copyright (C) 2014-2021 Dennis Sheirer + * Copyright (C) 2014-2022 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 @@ -18,6 +18,7 @@ */ package io.github.dsheirer.module.decode.p25.phase1; +import com.google.common.eventbus.Subscribe; import io.github.dsheirer.channel.state.ChangeChannelTimeoutEvent; import io.github.dsheirer.channel.state.DecoderState; import io.github.dsheirer.channel.state.DecoderStateEvent; @@ -33,7 +34,9 @@ import io.github.dsheirer.identifier.IdentifierClass; import io.github.dsheirer.identifier.IdentifierCollection; import io.github.dsheirer.identifier.MutableIdentifierCollection; import io.github.dsheirer.identifier.Role; +import io.github.dsheirer.identifier.patch.PatchGroupIdentifier; import io.github.dsheirer.identifier.patch.PatchGroupManager; +import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.event.DecodeEvent; @@ -229,7 +232,7 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList resetState(); } -/** + /** * Resets any temporal state details */ protected void resetState() @@ -244,6 +247,22 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList } } + /** + * Processes an identifier collection to harvest Patch Groups to preload when this channel is first starting up. + * @param preLoadDataContent containing an identifier collection with optional patch group identifier(s). + */ + @Subscribe + public void process(PatchGroupPreLoadDataContent preLoadDataContent) + { + for(Identifier identifier: preLoadDataContent.getData().getIdentifiers(Role.TO)) + { + if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier) + { + mPatchGroupManager.addPatchGroup(patchGroupIdentifier); + } + } + } + /** * Primary message processing method. */ @@ -2161,6 +2180,8 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList @Override public void start() { + mPatchGroupManager.clear(); + //Change the default (45-second) traffic channel timeout to 1 second if(mChannelType == ChannelType.TRAFFIC) { @@ -2176,5 +2197,6 @@ public class P25P1DecoderState extends DecoderState implements IChannelEventList @Override public void stop() { + mPatchGroupManager.clear(); } } diff --git a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java index 6e020afb..19daf59e 100644 --- a/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java +++ b/src/main/java/io/github/dsheirer/module/decode/p25/phase2/P25P2DecoderState.java @@ -1,26 +1,24 @@ /* + * ***************************************************************************** + * Copyright (C) 2014-2022 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 - * * ***************************************************************************** + * 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 + * **************************************************************************** */ package io.github.dsheirer.module.decode.p25.phase2; +import com.google.common.eventbus.Subscribe; import io.github.dsheirer.channel.IChannelDescriptor; import io.github.dsheirer.channel.state.ChangeChannelTimeoutEvent; import io.github.dsheirer.channel.state.DecoderStateEvent; @@ -36,7 +34,9 @@ import io.github.dsheirer.identifier.IdentifierUpdateListener; import io.github.dsheirer.identifier.MutableIdentifierCollection; import io.github.dsheirer.identifier.Role; import io.github.dsheirer.identifier.encryption.EncryptionKey; +import io.github.dsheirer.identifier.patch.PatchGroupIdentifier; import io.github.dsheirer.identifier.patch.PatchGroupManager; +import io.github.dsheirer.identifier.patch.PatchGroupPreLoadDataContent; import io.github.dsheirer.message.IMessage; import io.github.dsheirer.module.decode.DecoderType; import io.github.dsheirer.module.decode.event.DecodeEvent; @@ -145,6 +145,22 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie mEndPttOnFacchCounter = 0; } + /** + * Processes an identifier collection to harvest Patch Groups to preload when this channel is first starting up. + * @param preLoadDataContent containing an identifier collection with optional patch group identifier(s). + */ + @Subscribe + public void process(PatchGroupPreLoadDataContent preLoadDataContent) + { + for(Identifier identifier: preLoadDataContent.getData().getIdentifiers(Role.TO)) + { + if(identifier instanceof PatchGroupIdentifier patchGroupIdentifier) + { + mPatchGroupManager.addPatchGroup(patchGroupIdentifier); + } + } + } + /** * Primary message processing method. */ @@ -1242,6 +1258,8 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie @Override public void start() { + mPatchGroupManager.clear(); + //Change the default (45-second) traffic channel timeout to 1 second if(mChannelType == ChannelType.TRAFFIC) { @@ -1257,5 +1275,6 @@ public class P25P2DecoderState extends TimeslotDecoderState implements Identifie @Override public void stop() { + mPatchGroupManager.clear(); } }