From a5c0fbad58a139040a8fd3d5358565da69840d7a Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 31 Jan 2026 19:53:20 -0500 Subject: [PATCH] allow the user to adjust the frame timeout length when using frame timing at the bridge; ensure audio frames aren't greater then x2 the size of an expected audio frame; --- configs/bridge-config.example.yml | 2 ++ src/bridge/HostBridge.cpp | 15 ++++++++++++++- src/bridge/HostBridge.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/configs/bridge-config.example.yml b/configs/bridge-config.example.yml index 7040e242..ddf924b7 100644 --- a/configs/bridge-config.example.yml +++ b/configs/bridge-config.example.yml @@ -99,6 +99,8 @@ network: # (This allows the sending source to send audio as fast as it wants. This should not be used in combination # with 'udpRTPFrames'.) udpFrameTiming: false + # Amount of time (ms) to wait for UDP audio frames before missing a audio frame. + udpFrameTimeout: 40 # # Traffic Encryption Key (TEK) Configuration diff --git a/src/bridge/HostBridge.cpp b/src/bridge/HostBridge.cpp index 8a5613c3..776da099 100644 --- a/src/bridge/HostBridge.cpp +++ b/src/bridge/HostBridge.cpp @@ -173,6 +173,7 @@ HostBridge::HostBridge(const std::string& confFile) : m_udpUseULaw(false), m_udpUsrp(false), m_udpFrameTiming(false), + m_udpFrameTimeout(40U), m_udpFrameCnt(0U), m_tekAlgoId(P25DEF::ALGO_UNENCRYPT), m_tekKeyId(0U), @@ -1041,6 +1042,7 @@ bool HostBridge::createNetwork() m_udpReceiveAddress = networkConf["udpReceiveAddress"].as(); m_udpUsrp = networkConf["udpUsrp"].as(false); m_udpFrameTiming = networkConf["udpFrameTiming"].as(false); + m_udpFrameTimeout = (uint16_t)networkConf["udpFrameTimeout"].as(40U); if (m_udpUsrp) { m_udpMetadata = false; // USRP disables metadata due to USRP always having metadata @@ -1209,6 +1211,9 @@ bool HostBridge::createNetwork() } LogInfo(" UDP Audio USRP: %s", m_udpUsrp ? "yes" : "no"); LogInfo(" UDP Frame Timing: %s", m_udpFrameTiming ? "yes" : "no"); + if (m_udpFrameTiming) { + LogInfo(" UDP Frame Timeout: %u ms", m_udpFrameTimeout); + } } LogInfo(" Traffic Encrypted: %s", tekEnable ? "yes" : "no"); @@ -1307,6 +1312,11 @@ void HostBridge::processUDPAudio() return; } + if (length > AUDIO_SAMPLES_LENGTH_BYTES * 2U) { + LogWarning(LOG_NET, "UDP audio packet too large (%d bytes), dropping", length); + return; + } + // is the recieved audio frame *at least* raw PCM length of 320 bytes? if (!m_udpUseULaw && length < AUDIO_SAMPLES_LENGTH_BYTES) return; @@ -1405,6 +1415,7 @@ void HostBridge::processUDPAudio() } req->dstId = m_dstId; + m_udpPackets.push_back(req); } } @@ -2118,7 +2129,7 @@ void* HostBridge::threadUDPAudioProcess(void* arg) stopWatch.start(); ulong64_t lastFrameTime = 0U; - Timer frameTimeout = Timer(1000U, 0U, 22U); + Timer frameTimeout = Timer(1000U, 0U, bridge->m_udpFrameTimeout); while (!g_killed) { if (!HostBridge::s_running) { @@ -2133,6 +2144,8 @@ void* HostBridge::threadUDPAudioProcess(void* arg) // don't consider frame timeouts for RTP or USRP UDP streams (these will be properly timed anyway, we hope) if (!bridge->m_udpRTPFrames && !bridge->m_udpUsrp) { frameTimeout.clock(ms); + if (frameTimeout.isRunning() && bridge->m_udpPackets.size() > 0) + frameTimeout.start(); // clock the frame timeout timer if (frameTimeout.isRunning() && frameTimeout.hasExpired()) { frameTimeout.stop(); bridge->padSilenceAudio(bridge->m_udpSrcId, bridge->m_udpDstId); diff --git a/src/bridge/HostBridge.h b/src/bridge/HostBridge.h index 88c3b1dd..9c76c40f 100644 --- a/src/bridge/HostBridge.h +++ b/src/bridge/HostBridge.h @@ -164,6 +164,7 @@ private: bool m_udpUseULaw; bool m_udpUsrp; bool m_udpFrameTiming; + uint32_t m_udpFrameTimeout; uint32_t m_udpFrameCnt; uint8_t m_tekAlgoId;