From 10991a9c612872ebde65f1aebfb331e199df13af Mon Sep 17 00:00:00 2001 From: Dave Behnke <916775+dbehnke@users.noreply.github.com> Date: Thu, 1 Jan 2026 13:31:49 -0500 Subject: [PATCH 1/4] fix(audio): replace rand() with mt19937 for thread-safe UUIDs to prevent 0-byte recordings --- reflector/AudioRecorder.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/reflector/AudioRecorder.cpp b/reflector/AudioRecorder.cpp index 67f6ced..aeaba86 100644 --- a/reflector/AudioRecorder.cpp +++ b/reflector/AudioRecorder.cpp @@ -1,8 +1,8 @@ -#include "AudioRecorder.h" #include #include #include #include +#include // Opus settings for Voice 8kHz Mono #define SAMPLE_RATE 8000 @@ -41,10 +41,15 @@ std::string CAudioRecorder::Start(const std::string& directory) std::lock_guard lock(m_Mutex); Cleanup(); + // Use random_device for true randomness/seed + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist(0, 255); + // Generate UUIDv7 Filename uint8_t uuid[16]; uint8_t rand_bytes[10]; - for(int i=0; i<10; ++i) rand_bytes[i] = std::rand() & 0xFF; // Minimal entropy for now + for(int i=0; i<10; ++i) rand_bytes[i] = (uint8_t)dist(gen); struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -68,7 +73,7 @@ std::string CAudioRecorder::Start(const std::string& directory) } InitOpus(); - InitOgg(); + InitOgg(); // No longer calls srand m_StartTime = std::time(nullptr); m_TotalBytes = 0; @@ -91,8 +96,12 @@ void CAudioRecorder::InitOpus() void CAudioRecorder::InitOgg() { // Initialize Ogg stream with random serial - std::srand(std::time(nullptr)); - if (ogg_stream_init(&m_OggStream, std::rand()) != 0) { + // Use random_device for thread safety + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dist; // full int range + + if (ogg_stream_init(&m_OggStream, dist(gen)) != 0) { std::cerr << "AudioRecorder: Failed to init Ogg stream" << std::endl; return; } @@ -169,6 +178,7 @@ void CAudioRecorder::WriteOggPage(bool flush) m_File.write((const char*)m_OggPage.header, m_OggPage.header_len); m_File.write((const char*)m_OggPage.body, m_OggPage.body_len); m_TotalBytes += m_OggPage.header_len + m_OggPage.body_len; + m_File.flush(); } } From a02a7209fc96be3d356f5e63b6a09693ec63adb1 Mon Sep 17 00:00:00 2001 From: Dave Behnke <916775+dbehnke@users.noreply.github.com> Date: Thu, 1 Jan 2026 14:30:59 -0500 Subject: [PATCH 2/4] fix(audio): restore missing AudioRecorder.h include --- reflector/AudioRecorder.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/reflector/AudioRecorder.cpp b/reflector/AudioRecorder.cpp index aeaba86..f067d8d 100644 --- a/reflector/AudioRecorder.cpp +++ b/reflector/AudioRecorder.cpp @@ -1,3 +1,4 @@ +#include "AudioRecorder.h" #include #include #include From aad381c8854ce0f1369f1edf066f0ca58168c42f Mon Sep 17 00:00:00 2001 From: Dave Behnke <916775+dbehnke@users.noreply.github.com> Date: Thu, 1 Jan 2026 15:03:59 -0500 Subject: [PATCH 3/4] feat(reflector): rate limit orphaned frame warnings to once per minute --- reflector/Protocol.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/reflector/Protocol.cpp b/reflector/Protocol.cpp index 132d6fa..e8680e7 100644 --- a/reflector/Protocol.cpp +++ b/reflector/Protocol.cpp @@ -16,6 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include +#include +#include +#include #include "Defines.h" #include "Global.h" #include "Protocol.h" @@ -142,7 +146,17 @@ void CProtocol::OnDvFramePacketIn(std::unique_ptr &Frame, const else { std::cout << std::showbase << std::hex; - std::cout << "Orphaned Frame with ID " << ntohs(Frame->GetStreamId()) << std::noshowbase << std::dec << " on " << *Ip << std::endl; + // Rate limit warnings: only log once every 60 seconds per stream ID + static std::map last_warning; + std::time_t now = std::time(nullptr); + uint16_t sid = ntohs(Frame->GetStreamId()); + + if (last_warning.find(sid) == last_warning.end() || (now - last_warning[sid]) > 60) { + std::cout << "Orphaned Frame with ID " << std::hex << std::showbase << sid + << std::noshowbase << std::dec << " on " << *Ip + << " (Suppressed for 60s)" << std::endl; + last_warning[sid] = now; + } Frame.reset(); } //#endif From 878ab683ed7849693b70eafdf036e7a5a2210ab6 Mon Sep 17 00:00:00 2001 From: Dave Behnke <916775+dbehnke@users.noreply.github.com> Date: Thu, 1 Jan 2026 15:09:34 -0500 Subject: [PATCH 4/4] feat(reflector): rate limit late entry warnings to once per minute --- reflector/DMRMMDVMProtocol.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/reflector/DMRMMDVMProtocol.cpp b/reflector/DMRMMDVMProtocol.cpp index c36c921..eebc20f 100644 --- a/reflector/DMRMMDVMProtocol.cpp +++ b/reflector/DMRMMDVMProtocol.cpp @@ -19,6 +19,10 @@ #include +#include +#include +#include +#include #include "Global.h" #include "DMRMMDVMClient.h" #include "DMRMMDVMProtocol.h" @@ -677,7 +681,16 @@ bool CDmrmmdvmProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffe if ( !stream ) { std::cout << std::showbase << std::hex; - std::cout << "Late entry DMR voice frame, creating DMR header for DMR stream ID " << ntohl(uiStreamId) << std::noshowbase << std::dec << " on " << Ip << std::endl; + static std::map last_late_entry; + std::time_t now = std::time(nullptr); + uint32_t sid = ntohl(uiStreamId); + + if (last_late_entry.find(sid) == last_late_entry.end() || (now - last_late_entry[sid]) > 60) { + std::cout << "Late entry DMR voice frame, creating DMR header for DMR stream ID " << std::hex << std::showbase << sid + << std::noshowbase << std::dec << " on " << Ip + << " (Suppressed for 60s)" << std::endl; + last_late_entry[sid] = now; + } std::cout << std::noshowbase << std::dec; uint8_t cmd;