From 897930d4f1698ca643adef436c3b722ea40cffe6 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Tue, 24 Feb 2026 13:32:27 -0500 Subject: [PATCH] properly set the FIRST seq (when seq is reset to 0) as a marker; because JSB is *REALLY* hell bent on this, implement continuous RTP seq to make him happy; --- configs/bridge-config.example.yml | 5 +++++ src/bridge/HostBridge.Analog.cpp | 5 ++++- src/bridge/HostBridge.DMR.cpp | 5 ++++- src/bridge/HostBridge.P25.cpp | 5 ++++- src/bridge/HostBridge.cpp | 22 +++++++++++++++++++--- src/bridge/HostBridge.h | 2 ++ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/configs/bridge-config.example.yml b/configs/bridge-config.example.yml index 6e3ddf45..1f7ee5ba 100644 --- a/configs/bridge-config.example.yml +++ b/configs/bridge-config.example.yml @@ -182,6 +182,11 @@ system: # (This allows the sending source to send audio as fast as it wants. This should not be used in combination # with 'udpFrameTiming', and is intended for diagnostic purposes only.) udpIgnoreRTPTiming: false + # Flag indicating UDP audio RTP sequence numbers should be continuous across packets and only reset to 0 + # upon sequence rollover. (DO NOT use this option for back-to-back transcoding with another instance of the bridge, + # as it may cause issues with RTP sequence number handling, this option is intended for third-party RTP consumers + # who idiotically implement RTP and do not properly adhere to marker bits.) + udpRTPContinuousSeq: false # Flag indicating UDP audio should be encoded using G.711 uLaw. # NOTE: This flag is only applicable when sending audio via RTP. udpUseULaw: false diff --git a/src/bridge/HostBridge.Analog.cpp b/src/bridge/HostBridge.Analog.cpp index 89edd659..24aefb09 100644 --- a/src/bridge/HostBridge.Analog.cpp +++ b/src/bridge/HostBridge.Analog.cpp @@ -114,7 +114,10 @@ void HostBridge::processAnalogNetwork(uint8_t* buffer, uint32_t length) m_rxStartTime = 0U; m_rxStreamId = 0U; - m_rtpSeqNo = 0U; + if (!m_udpRTPContinuousSeq) { + m_rtpInitialFrame = false; + m_rtpSeqNo = 0U; + } m_rtpTimestamp = INVALID_TS; m_network->resetAnalog(); return; diff --git a/src/bridge/HostBridge.DMR.cpp b/src/bridge/HostBridge.DMR.cpp index 0b963da6..7b946f91 100644 --- a/src/bridge/HostBridge.DMR.cpp +++ b/src/bridge/HostBridge.DMR.cpp @@ -199,7 +199,10 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length) m_rxStartTime = 0U; m_rxStreamId = 0U; - m_rtpSeqNo = 0U; + if (!m_udpRTPContinuousSeq) { + m_rtpInitialFrame = false; + m_rtpSeqNo = 0U; + } m_rtpTimestamp = INVALID_TS; m_network->resetDMR(slotNo); return; diff --git a/src/bridge/HostBridge.P25.cpp b/src/bridge/HostBridge.P25.cpp index e9681602..121aeda6 100644 --- a/src/bridge/HostBridge.P25.cpp +++ b/src/bridge/HostBridge.P25.cpp @@ -211,7 +211,10 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length) m_rxStartTime = 0U; m_rxStreamId = 0U; - m_rtpSeqNo = 0U; + if (!m_udpRTPContinuousSeq) { + m_rtpInitialFrame = false; + m_rtpSeqNo = 0U; + } m_rtpTimestamp = INVALID_TS; m_network->resetP25(); return; diff --git a/src/bridge/HostBridge.cpp b/src/bridge/HostBridge.cpp index dc476e0a..5e43c064 100644 --- a/src/bridge/HostBridge.cpp +++ b/src/bridge/HostBridge.cpp @@ -212,6 +212,7 @@ HostBridge::HostBridge(const std::string& confFile) : m_udpReceiveAddress("127.0.0.1"), m_udpRTPFrames(false), m_udpIgnoreRTPTiming(false), + m_udpRTPContinuousSeq(false), m_udpUseULaw(false), m_udpUsrp(false), m_udpFrameTiming(false), @@ -256,6 +257,7 @@ HostBridge::HostBridge(const std::string& confFile) : m_networkWatchdog(1000U, 0U, 1500U), m_trace(false), m_debug(false), + m_rtpInitialFrame(false), m_rtpSeqNo(0U), m_rtpTimestamp(INVALID_TS), m_udpNetPktSeq(0U), @@ -650,7 +652,10 @@ int HostBridge::run() m_rxStartTime = 0U; m_rxStreamId = 0U; - m_rtpSeqNo = 0U; + if (!m_udpRTPContinuousSeq) { + m_rtpInitialFrame = false; + m_rtpSeqNo = 0U; + } m_rtpTimestamp = INVALID_TS; m_network->resetDMR(0U); @@ -1029,6 +1034,7 @@ bool HostBridge::readParams() m_udpRTPFrames = systemConf["udpRTPFrames"].as(false); m_udpIgnoreRTPTiming = systemConf["udpIgnoreRTPTiming"].as(false); + m_udpRTPContinuousSeq = systemConf["udpRTPContinuousSeq"].as(false); m_udpUseULaw = systemConf["udpUseULaw"].as(false); if (m_udpRTPFrames) { m_udpUsrp = false; // RTP disabled USRP @@ -1043,6 +1049,8 @@ bool HostBridge::readParams() if (m_udpIgnoreRTPTiming) ::LogWarning(LOG_HOST, "Ignoring RTP timing, audio frames will be processed as they arrive."); + if (m_udpRTPContinuousSeq) + ::LogWarning(LOG_HOST, "Using continuous RTP sequence numbers, sequence numbers will not reset at the start of a new call."); yaml::Node tekConf = systemConf["tek"]; bool tekEnable = tekConf["enable"].as(false); @@ -1127,6 +1135,7 @@ bool HostBridge::readParams() if (m_udpRTPFrames) { LogInfo(" UDP Audio Use uLaw Encoding: %s", m_udpUseULaw ? "yes" : "no"); LogInfo(" UDP Audio Ignore RTP Timing: %s", m_udpIgnoreRTPTiming ? "yes" : "no"); + LogInfo(" UDP Audio Use Continuous RTP Sequence Numbers: %s", m_udpRTPContinuousSeq ? "yes" : "no"); } LogInfo(" UDP Audio USRP: %s", m_udpUsrp ? "yes" : "no"); LogInfo(" UDP Frame Timing: %s", m_udpFrameTiming ? "yes" : "no"); @@ -1473,6 +1482,8 @@ void HostBridge::writeUDPAudio(uint32_t srcId, uint32_t dstId, uint8_t* pcm, uin // are we sending RTP audio frames? if (m_udpRTPFrames) { + LogDebug(LOG_HOST, "Generating RTP frame for UDP audio, srcId = %u, dstId = %u, pcmLength = %u, prevRtpSeq = %u", srcId, dstId, pcmLength, m_rtpSeqNo); + uint8_t* rtpFrame = generateRTPHeaders(pcmLength, m_rtpSeqNo); if (rtpFrame != nullptr) { // are we sending metadata with the RTP frames? @@ -1638,8 +1649,10 @@ uint8_t* HostBridge::generateRTPHeaders(uint8_t msgLen, uint16_t& rtpSeq) header.setSSRC(m_network->getPeerId()); // set the marker for the start of a stream - if (rtpSeq == 0U) + if (rtpSeq == 0U && !m_rtpInitialFrame) { + m_rtpInitialFrame = true; header.setMarker(true); + } uint8_t* buffer = new uint8_t[RTP_HEADER_LENGTH_BYTES + msgLen]; ::memset(buffer, 0x00U, RTP_HEADER_LENGTH_BYTES + msgLen); @@ -1769,7 +1782,10 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId) m_p25N = 0U; m_analogN = 0U; - m_rtpSeqNo = 0U; + if (!m_udpRTPContinuousSeq) { + m_rtpInitialFrame = false; + m_rtpSeqNo = 0U; + } m_rtpTimestamp = INVALID_TS; m_p25Crypto->clearMI(); diff --git a/src/bridge/HostBridge.h b/src/bridge/HostBridge.h index eb584b88..d2640686 100644 --- a/src/bridge/HostBridge.h +++ b/src/bridge/HostBridge.h @@ -225,6 +225,7 @@ private: bool m_udpRTPFrames; bool m_udpIgnoreRTPTiming; + bool m_udpRTPContinuousSeq; bool m_udpUseULaw; bool m_udpUsrp; bool m_udpFrameTiming; @@ -294,6 +295,7 @@ private: static bool s_running; + bool m_rtpInitialFrame; uint16_t m_rtpSeqNo; uint32_t m_rtpTimestamp;