From df412846820722a43e2ef47cd51e27f3462103d1 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 19 Jan 2016 19:34:49 +0000 Subject: [PATCH] Handle missing frames. --- DMRSlot.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++++++---- DMRSlot.h | 8 ++++ Makefile | 2 +- 3 files changed, 133 insertions(+), 10 deletions(-) diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 0d883c2..8f6da1c 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -47,14 +47,21 @@ m_embeddedLC(), m_lc(NULL), m_seqNo(0U), m_n(0U), -m_networkWatchdog(1000U, 2U), +m_lastFrame(NULL), +m_networkWatchdog(1000U, 1U), m_timeoutTimer(1000U, timeout), +m_packetTimer(1000U, 0U, 200U), +m_elapsed(), +m_frames(0U), +m_lost(0U), m_fp(NULL) { + m_lastFrame = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U]; } CDMRSlot::~CDMRSlot() { + delete[] m_lastFrame; } void CDMRSlot::writeModem(unsigned char *data) @@ -141,8 +148,6 @@ void CDMRSlot::writeModem(unsigned char *data) writeNetwork(data, DT_VOICE_PI_HEADER); writeQueue(data); - - LogMessage("DMR Slot %u, received PI header", m_slotNo); } else if (dataType == DT_TERMINATOR_WITH_LC) { if (m_state != RS_RELAYING_RF_AUDIO) return; @@ -342,6 +347,7 @@ void CDMRSlot::writeEndOfTransmission() m_networkWatchdog.stop(); m_timeoutTimer.stop(); + m_packetTimer.stop(); delete m_lc; m_lc = NULL; @@ -389,6 +395,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_timeoutTimer.start(); + m_frames = 0U; + // 540ms of idle to give breathing space for lost frames for (unsigned int i = 0U; i < 9U; i++) writeQueue(m_idle); @@ -453,7 +461,9 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) writeFile(data); closeFile(); #endif - LogMessage("DMR Slot %u, received network end of voice transmission", m_slotNo); + // We've received the voice header and terminator haven't we? + m_frames += 2U; + LogMessage("DMR Slot %u, received network end of voice transmission, %u%% packet loss", m_slotNo, (m_lost * 100U) / m_frames); } else if (dataType == DT_DATA_HEADER) { if (m_state == RS_RELAYING_NETWORK_DATA) return; @@ -471,10 +481,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_seqNo = 0U; - m_n = 0U; - - // Put a small delay into starting retransmission + // Put a small delay into starting transmission writeQueue(m_idle); writeQueue(m_idle); @@ -482,6 +489,7 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) writeQueue(data); m_state = RS_RELAYING_NETWORK_DATA; + // setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO()); // m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId()); @@ -492,6 +500,16 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) if (m_state != RS_RELAYING_NETWORK_AUDIO) return; + // Initialise the lost packet data + if (m_frames == 0U) { + m_seqNo = dmrData.getSeqNo(); + m_n = dmrData.getN(); + m_elapsed.start(); + m_lost = 0U; + } else { + insertSilence(dmrData.getSeqNo()); + } + // Convert the Audio Sync to be from the BS CDMRSync sync; sync.addSync(data + 2U, DST_BS_AUDIO); @@ -505,6 +523,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) writeQueue(data); + m_packetTimer.start(); + m_frames++; + + // Save details in case we need to infill data + m_seqNo = dmrData.getSeqNo(); + m_n = dmrData.getN(); + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + #if defined(DUMP_DMR) writeFile(data); #endif @@ -512,6 +538,16 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) if (m_state != RS_RELAYING_NETWORK_AUDIO) return; + // Initialise the lost packet data + if (m_frames == 0U) { + m_seqNo = dmrData.getSeqNo(); + m_n = dmrData.getN(); + m_elapsed.start(); + m_lost = 0U; + } else { + insertSilence(dmrData.getSeqNo()); + } + unsigned char fid = m_lc->getFID(); if (fid == FID_ETSI || fid == FID_DMRA) ; // AMBE FEC @@ -527,6 +563,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) writeQueue(data); + m_packetTimer.start(); + m_frames++; + + // Save details in case we need to infill data + m_seqNo = dmrData.getSeqNo(); + m_n = dmrData.getN(); + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + #if defined(DUMP_DMR) writeFile(data); #endif @@ -560,13 +604,31 @@ void CDMRSlot::clock(unsigned int ms) m_networkWatchdog.clock(ms); if (m_networkWatchdog.hasExpired()) { - LogMessage("DMR Slot %u, network watchdog has expired", m_slotNo); + // We've received the voice header haven't we? + m_frames += 1U; + LogMessage("DMR Slot %u, network watchdog has expired, %u%% packet loss", m_slotNo, (m_lost * 100U) / m_frames); writeEndOfTransmission(); #if defined(DUMP_DMR) closeFile(); #endif } } + + if (m_state == RS_RELAYING_NETWORK_AUDIO) { + m_packetTimer.clock(ms); + + if (m_packetTimer.hasExpired()) { + unsigned int frames = m_elapsed.elapsed() / DMR_SLOT_TIME; + + if (frames > m_frames) { + unsigned int count = frames - m_frames; + if (count > 5U) + insertSilence(m_seqNo + count - 2U); + } + + m_packetTimer.start(); + } + } } void CDMRSlot::writeQueue(const unsigned char *data) @@ -739,3 +801,56 @@ void CDMRSlot::closeFile() m_fp = NULL; } } + +void CDMRSlot::insertSilence(unsigned char newSeqNo) +{ + // Check to see if we have any spaces to fill + unsigned char seqNo = m_seqNo + 1U; + if (newSeqNo == seqNo) + return; + + unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; + ::memcpy(data, m_lastFrame, DMR_FRAME_LENGTH_BYTES + 2U); + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + unsigned char n = (m_n + 1U) % 6U; + + unsigned int count = 0U; + while (seqNo < newSeqNo) { + if (n == 0U) { + // Add the voice sync + CDMRSync sync; + sync.addSync(data + 2U, DST_BS_AUDIO); + } else { + // Set the embedded signalling to be nulls + ::memset(data + 16U, 0x00U, 5U); + + // Change the color code in the EMB + // XXX Note that the PI flag is lost here + CEMB emb; + emb.setPI(false); + emb.setLCSS(0U); + emb.setColorCode(m_colorCode); + emb.getData(data + 2U); + } + + data[0U] = TAG_DATA; + data[1U] = 0x00U; + + writeQueue(data); + + m_seqNo = seqNo; + m_n = n; + + count++; + m_frames++; + m_lost++; + + seqNo++; + n = (n + 1U) % 6U; + } + + LogMessage("DMR Slot %u, inserted %u audio frames", m_slotNo, count); +} diff --git a/DMRSlot.h b/DMRSlot.h index f26472d..aef15f6 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -20,6 +20,7 @@ #define DMRSlot_H #include "HomebrewDMRIPSC.h" +#include "StopWatch.h" #include "EmbeddedLC.h" #include "RingBuffer.h" #include "DMRSlot.h" @@ -53,8 +54,13 @@ private: CLC* m_lc; unsigned char m_seqNo; unsigned char m_n; + unsigned char* m_lastFrame; CTimer m_networkWatchdog; CTimer m_timeoutTimer; + CTimer m_packetTimer; + CStopWatch m_elapsed; + unsigned int m_frames; + unsigned int m_lost; FILE* m_fp; static unsigned int m_colorCode; @@ -78,6 +84,8 @@ private: bool writeFile(const unsigned char* data); void closeFile(); + void insertSilence(unsigned char seqNo); + static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP); }; diff --git a/Makefile b/Makefile index 8badee8..1df18c4 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ DMRData.o: DMRData.cpp DMRData.h DMRDefines.h Utils.h Log.h $(CC) $(CFLAGS) -c DMRData.cpp DMRSlot.o: DMRSlot.cpp DMRSlot.h DMRData.h Modem.h HomebrewDMRIPSC.h Defines.h Log.h EmbeddedLC.h RingBuffer.h Timer.h LC.h SlotType.h DMRSync.h FullLC.h \ - EMB.h CRC.h CSBK.h ShortLC.h Utils.h Display.h + EMB.h CRC.h CSBK.h ShortLC.h Utils.h Display.h StopWatch.h $(CC) $(CFLAGS) -c DMRSlot.cpp DMRSync.o: DMRSync.cpp DMRSync.h DMRDefines.h