From 683e71e03557f63ed352d79d5b4266bf85dd4cf3 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Thu, 15 Jan 2026 09:29:48 -0500 Subject: [PATCH] EXPERIMENTAL (and untested): allow source ID overriding for parrot playback, this feature will rewrite the source ID to a static ID configured in the FNE configuration, for P25, NXDN and Analog this rewrite is striaghtfoward, for DMR this will likely work oddly due to the way DMR has source ID data embedded in the transited data frames; --- configs/fne-config.example.yml | 2 ++ src/fne/network/FNENetwork.cpp | 9 +++++++++ src/fne/network/FNENetwork.h | 1 + src/fne/network/callhandler/TagAnalogData.cpp | 8 ++++++++ src/fne/network/callhandler/TagDMRData.cpp | 15 +++++++++++++++ src/fne/network/callhandler/TagNXDNData.cpp | 8 ++++++++ src/fne/network/callhandler/TagP25Data.cpp | 9 +++++++++ 7 files changed, 52 insertions(+) diff --git a/configs/fne-config.example.yml b/configs/fne-config.example.yml index 2218f6c2..eb44d760 100644 --- a/configs/fne-config.example.yml +++ b/configs/fne-config.example.yml @@ -139,6 +139,8 @@ master: parrotGrantDemand: true # Flag indicating whether or not a parrot TG call will only be sent to the originating peer. parrotOnlyToOrginiatingPeer: false + # Source ID to override parrot TG calls with (0 for no override). + parrotOverrideSrcId: 0 # Flag indicating whether or not P25 OTAR KMF services are enabled. kmfServicesEnabled: false diff --git a/src/fne/network/FNENetwork.cpp b/src/fne/network/FNENetwork.cpp index 04ad185d..e607ec0f 100644 --- a/src/fne/network/FNENetwork.cpp +++ b/src/fne/network/FNENetwork.cpp @@ -86,6 +86,7 @@ FNENetwork::FNENetwork(HostFNE* host, const std::string& address, uint16_t port, m_parrotDelayTimer(1000U, 0U, parrotDelay), m_parrotGrantDemand(parrotGrantDemand), m_parrotOnlyOriginating(false), + m_parrotOverrideSrcId(0U), m_kmfServicesEnabled(false), m_ridLookup(nullptr), m_tidLookup(nullptr), @@ -240,6 +241,11 @@ void FNENetwork::setOptions(yaml::Node& conf, bool printOptions) } m_parrotOnlyOriginating = conf["parrotOnlyToOrginiatingPeer"].as(false); + m_parrotOverrideSrcId = conf["parrotOverrideSrcId"].as(0U); + if (m_parrotOverrideSrcId > 0U && m_parrotOverrideSrcId > 16777200U) { + LogWarning(LOG_MASTER, "Parrot Override Source ID %u is out of valid range (1 - 16777200), disabling override.", m_parrotOverrideSrcId); + m_parrotOverrideSrcId = 0U; + } // jitter buffer configuration yaml::Node jitterConf = conf["jitterBuffer"]; @@ -378,6 +384,9 @@ void FNENetwork::setOptions(yaml::Node& conf, bool printOptions) LogInfo(" Global Jitter Buffer Default Max Wait: %u microseconds", m_jitterMaxWait); } LogInfo(" Parrot Repeat to Only Originating Peer: %s", m_parrotOnlyOriginating ? "yes" : "no"); + if (m_parrotOverrideSrcId != 0U) { + LogInfo(" Parrot Repeat Source ID Override: %u", m_parrotOverrideSrcId); + } LogInfo(" P25 OTAR KMF Services Enabled: %s", m_kmfServicesEnabled ? "yes" : "no"); LogInfo(" P25 OTAR KMF Listening Address: %s", m_address.c_str()); LogInfo(" P25 OTAR KMF Listening Port: %u", kmfOtarPort); diff --git a/src/fne/network/FNENetwork.h b/src/fne/network/FNENetwork.h index e2ea4274..1d2a1974 100644 --- a/src/fne/network/FNENetwork.h +++ b/src/fne/network/FNENetwork.h @@ -323,6 +323,7 @@ namespace network Timer m_parrotDelayTimer; bool m_parrotGrantDemand; bool m_parrotOnlyOriginating; + uint32_t m_parrotOverrideSrcId; bool m_kmfServicesEnabled; diff --git a/src/fne/network/callhandler/TagAnalogData.cpp b/src/fne/network/callhandler/TagAnalogData.cpp index bbde7737..1773c4ce 100644 --- a/src/fne/network/callhandler/TagAnalogData.cpp +++ b/src/fne/network/callhandler/TagAnalogData.cpp @@ -441,6 +441,14 @@ void TagAnalogData::playbackParrot() auto& pkt = m_parrotFrames[0]; m_parrotFrames.lock(); if (pkt.buffer != nullptr) { + // has the override source ID been set? + if (m_network->m_parrotOverrideSrcId > 0U) { + pkt.srcId = m_network->m_parrotOverrideSrcId; + + // override source ID + SET_UINT24(m_network->m_parrotOverrideSrcId, pkt.buffer, 5U); + } + m_lastParrotPeerId = pkt.peerId; m_lastParrotSrcId = pkt.srcId; m_lastParrotDstId = pkt.dstId; diff --git a/src/fne/network/callhandler/TagDMRData.cpp b/src/fne/network/callhandler/TagDMRData.cpp index 697dac72..53941353 100644 --- a/src/fne/network/callhandler/TagDMRData.cpp +++ b/src/fne/network/callhandler/TagDMRData.cpp @@ -691,6 +691,21 @@ void TagDMRData::playbackParrot() auto& pkt = m_parrotFrames[0]; m_parrotFrames.lock(); if (pkt.buffer != nullptr) { + // has the override source ID been set? + if (m_network->m_parrotOverrideSrcId > 0U) { + pkt.srcId = m_network->m_parrotOverrideSrcId; + + // override source ID + SET_UINT24(m_network->m_parrotOverrideSrcId, pkt.buffer, 5U); + + /* + ** bryanb: DMR is problematic because the VOICE_LC_HEADER, TERMINATOR_WITH_LC, + ** and VOICE_PI_HEADER all contain the source ID in the LC portion of the frame + ** and because we are not updating that the parrot playback will appear to come from + ** the original source ID in those frames + */ + } + m_lastParrotPeerId = pkt.peerId; m_lastParrotSrcId = pkt.srcId; m_lastParrotDstId = pkt.dstId; diff --git a/src/fne/network/callhandler/TagNXDNData.cpp b/src/fne/network/callhandler/TagNXDNData.cpp index 243cd754..4a6d3eb8 100644 --- a/src/fne/network/callhandler/TagNXDNData.cpp +++ b/src/fne/network/callhandler/TagNXDNData.cpp @@ -720,6 +720,14 @@ void TagNXDNData::playbackParrot() auto& pkt = m_parrotFrames[0]; m_parrotFrames.lock(); if (pkt.buffer != nullptr) { + // has the override source ID been set? + if (m_network->m_parrotOverrideSrcId > 0U) { + pkt.srcId = m_network->m_parrotOverrideSrcId; + + // override source ID + SET_UINT24(m_network->m_parrotOverrideSrcId, pkt.buffer, 5U); + } + m_lastParrotPeerId = pkt.peerId; m_lastParrotSrcId = pkt.srcId; m_lastParrotDstId = pkt.dstId; diff --git a/src/fne/network/callhandler/TagP25Data.cpp b/src/fne/network/callhandler/TagP25Data.cpp index 41bd7a36..346db37e 100644 --- a/src/fne/network/callhandler/TagP25Data.cpp +++ b/src/fne/network/callhandler/TagP25Data.cpp @@ -802,6 +802,15 @@ void TagP25Data::playbackParrot() auto& pkt = m_parrotFrames[0]; m_parrotFrames.lock(); if (pkt.buffer != nullptr) { + // has the override source ID been set? + if (m_network->m_parrotOverrideSrcId > 0U) { + pkt.srcId = m_network->m_parrotOverrideSrcId; + + // override source ID + SET_UINT24(m_network->m_parrotOverrideSrcId, pkt.buffer, 5U); + } + + // is this the first parrot frame? if (m_parrotFirstFrame) { if (m_network->m_parrotGrantDemand) { uint32_t srcId = pkt.srcId;