From 220cd0a0f92c14b49c41ed95a3dd2d5879ec1a29 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 28 Nov 2017 10:09:29 +0000 Subject: [PATCH] Revert "Full integration of the jitter buffer into DMR." This reverts commit e1800c0fe03f470475f1daba1a284cf898868e94. --- DMRControl.cpp | 4 +- DMRControl.h | 2 +- DMRNetwork.cpp | 5 +- DMRSlot.cpp | 191 ++++++++++++++++++++++++++++++++++++++++------- DMRSlot.h | 13 +++- JitterBuffer.cpp | 46 ++++++------ JitterBuffer.h | 8 +- MMDVMHost.cpp | 3 +- 8 files changed, 205 insertions(+), 67 deletions(-) diff --git a/DMRControl.cpp b/DMRControl.cpp index b0ef7f2..4d7c668 100644 --- a/DMRControl.cpp +++ b/DMRControl.cpp @@ -21,7 +21,7 @@ #include #include -CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi) : +CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter) : m_colorCode(colorCode), m_modem(modem), m_network(network), @@ -38,7 +38,7 @@ m_lookup(lookup) // Load black and white lists to DMRAccessControl CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id); - CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi); + CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, jitter); } CDMRControl::~CDMRControl() diff --git a/DMRControl.h b/DMRControl.h index 22a28c4..7b7b17c 100644 --- a/DMRControl.h +++ b/DMRControl.h @@ -31,7 +31,7 @@ class CDMRControl { public: - CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi); + CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector& prefixes, const std::vector& blacklist, const std::vector& whitelist, const std::vector& slot1TGWhitelist, const std::vector& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter); ~CDMRControl(); bool processWakeup(const unsigned char* data); diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index 4ff02f4..e840cdd 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -172,14 +172,13 @@ bool CDMRNetwork::read(CDMRData& data) if (wanted) { unsigned char seqNo = m_buffer[4U]; - m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); + m_jitterBuffers[slotNo]->addData(m_buffer, seqNo); } } } for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { - unsigned int length = 0U; - JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer, length); + JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer); if (status != JBS_NO_DATA) { unsigned char seqNo = m_buffer[4U]; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 9c21453..5f64b0c 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -45,6 +45,9 @@ unsigned int CDMRSlot::m_hangCount = 3U * 17U; CRSSIInterpolator* CDMRSlot::m_rssiMapper = NULL; +unsigned int CDMRSlot::m_jitterTime = 300U; +unsigned int CDMRSlot::m_jitterSlots = 5U; + unsigned char* CDMRSlot::m_idle = NULL; FLCO CDMRSlot::m_flco1; @@ -84,12 +87,15 @@ m_netTalkerId(TALKER_ID_NONE), m_rfLC(NULL), m_netLC(NULL), m_rfSeqNo(0U), +m_netSeqNo(0U), m_rfN(0U), m_netN(0U), m_networkWatchdog(1000U, 0U, 1500U), m_rfTimeoutTimer(1000U, timeout), m_netTimeoutTimer(1000U, timeout), +m_packetTimer(1000U, 0U, 50U), m_interval(), +m_elapsed(), m_rfFrames(0U), m_netFrames(0U), m_netLost(0U), @@ -100,6 +106,8 @@ m_rfErrs(0U), m_netErrs(0U), m_rfTimeout(false), m_netTimeout(false), +m_lastFrame(NULL), +m_lastFrameValid(false), m_rssi(0U), m_maxRSSI(0U), m_minRSSI(0U), @@ -108,6 +116,7 @@ m_rssiCount(0U), m_fp(NULL) { m_rfTalkerAlias = new unsigned char[32U]; + m_lastFrame = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U]; m_rfEmbeddedData = new CDMREmbeddedData[2U]; m_netEmbeddedData = new CDMREmbeddedData[2U]; @@ -119,6 +128,7 @@ CDMRSlot::~CDMRSlot() { delete[] m_rfEmbeddedData; delete[] m_netEmbeddedData; + delete[] m_lastFrame; delete[] m_rfTalkerAlias; } @@ -897,9 +907,6 @@ void CDMRSlot::writeEndRF(bool writeEnd) } } - if (m_network != NULL) - m_network->reset(m_slotNo); - m_rfTimeoutTimer.stop(); m_rfTimeout = false; @@ -919,6 +926,8 @@ void CDMRSlot::writeEndNet(bool writeEnd) m_display->clearDMR(m_slotNo); + m_lastFrameValid = false; + if (writeEnd && !m_netTimeout) { // Create a dummy start end frame unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -945,11 +954,9 @@ void CDMRSlot::writeEndNet(bool writeEnd) } } - if (m_network != NULL) - m_network->reset(m_slotNo); - m_networkWatchdog.stop(); m_netTimeoutTimer.stop(); + m_packetTimer.stop(); m_netTimeout = false; m_netFrames = 0U; @@ -971,20 +978,13 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE) return; - unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; - dmrData.getData(data + 2U); - - if (dmrData.isMissing()) { - m_netN = (m_netN + 1U) % 6U; - m_netLost++; - repeatFrame(data + 2U); - } else { - m_netN = dmrData.getN(); - m_networkWatchdog.start(); - } + m_networkWatchdog.start(); unsigned char dataType = dmrData.getDataType(); + unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; + dmrData.getData(data + 2U); + if (dataType == DT_VOICE_LC_HEADER) { if (m_netState == RS_NET_AUDIO) return; @@ -1027,6 +1027,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; + m_lastFrameValid = false; + m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1044,6 +1046,9 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + for (unsigned int i = 0U; i < m_jitterSlots; i++) + writeQueueNet(m_idle); + if (m_duplex) { for (unsigned int i = 0U; i < NO_HEADERS_DUPLEX; i++) writeQueueNet(data); @@ -1075,6 +1080,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netLC = lc; + m_lastFrameValid = false; + m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1083,6 +1090,9 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + for (unsigned int i = 0U; i < m_jitterSlots; i++) + writeQueueNet(m_idle); + // Create a dummy start frame unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -1256,6 +1266,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netEmbeddedData[0U].setLC(*m_netLC); m_netEmbeddedData[1U].setLC(*m_netLC); + m_lastFrameValid = false; + m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1264,6 +1276,9 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + for (unsigned int i = 0U; i < m_jitterSlots; i++) + writeQueueNet(m_idle); + // Create a dummy start frame unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -1325,8 +1340,15 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) CSync::addDMRAudioSync(data + 2U, m_duplex); // Initialise the lost packet data - if (m_netFrames == 0U) + if (m_netFrames == 0U) { + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + m_lastFrameValid = true; + m_netSeqNo = dmrData.getSeqNo(); + m_netN = dmrData.getN(); m_netLost = 0U; + } else { + insertSilence(data, dmrData.getSeqNo()); + } if (!m_netTimeout) writeQueueNet(data); @@ -1336,8 +1358,15 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netEmbeddedData[m_netEmbeddedWriteN].reset(); + m_packetTimer.start(); + m_elapsed.start(); + m_netFrames++; + // Save details in case we need to infill data + m_netSeqNo = dmrData.getSeqNo(); + m_netN = dmrData.getN(); + #if defined(DUMP_DMR) writeFile(data); #endif @@ -1465,14 +1494,28 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[1U] = 0x00U; // Initialise the lost packet data - if (m_netFrames == 0U) + if (m_netFrames == 0U) { + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + m_lastFrameValid = true; + m_netSeqNo = dmrData.getSeqNo(); + m_netN = dmrData.getN(); m_netLost = 0U; + } else { + insertSilence(data, dmrData.getSeqNo()); + } if (!m_netTimeout) writeQueueNet(data); + m_packetTimer.start(); + m_elapsed.start(); + m_netFrames++; + // Save details in case we need to infill data + m_netSeqNo = dmrData.getSeqNo(); + m_netN = dmrData.getN(); + #if defined(DUMP_DMR) writeFile(data); #endif @@ -1682,6 +1725,21 @@ void CDMRSlot::clock() } } } + + if (m_netState == RS_NET_AUDIO) { + m_packetTimer.clock(ms); + + if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) { + unsigned int elapsed = m_elapsed.elapsed(); + if (elapsed >= m_jitterTime) { + LogDebug("DMR Slot %u, lost audio for %ums filling in", m_slotNo, elapsed); + insertSilence(m_jitterSlots); + m_elapsed.start(); + } + + m_packetTimer.start(); + } + } } void CDMRSlot::writeQueueRF(const unsigned char *data) @@ -1755,7 +1813,7 @@ void CDMRSlot::writeQueueNet(const unsigned char *data) m_queue.addData(data, len); } -void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper) +void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter) { assert(modem != NULL); assert(display != NULL); @@ -1774,6 +1832,9 @@ void CDMRSlot::init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData m_rssiMapper = rssiMapper; + m_jitterTime = jitter; + m_jitterSlots = jitter / DMR_SLOT_TIME; + m_idle = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U]; ::memcpy(m_idle, DMR_IDLE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); @@ -1919,16 +1980,88 @@ void CDMRSlot::closeFile() } } -void CDMRSlot::repeatFrame(unsigned char* data) +bool CDMRSlot::insertSilence(const unsigned char* data, unsigned char seqNo) { - if (m_netN == 0U) { - CSync::addDMRAudioSync(data, m_duplex); - } else { - m_netEmbeddedLC.getData(data, 0U); + assert(data != NULL); - CDMREMB emb; - emb.setColorCode(m_colorCode); - emb.setLCSS(0U); - emb.getData(data); + // Check to see if we have any spaces to fill? + unsigned char seq = m_netSeqNo + 1U; + if (seq == seqNo) { + // Just copy the data, nothing else to do here + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + m_lastFrameValid = true; + return true; + } + + unsigned int oldSeqNo = m_netSeqNo + 1U; + unsigned int newSeqNo = seqNo; + + unsigned int count; + if (newSeqNo > oldSeqNo) + count = newSeqNo - oldSeqNo; + else + count = (256U + newSeqNo) - oldSeqNo; + + if (count >= 10U) + return false; + + insertSilence(count); + + ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); + m_lastFrameValid = true; + + return true; +} + +void CDMRSlot::insertSilence(unsigned int count) +{ + unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U]; + + if (m_lastFrameValid) { + ::memcpy(data, m_lastFrame, 2U); // The control data + ::memcpy(data + 2U, m_lastFrame + 24U + 2U, 9U); // Copy the last audio block to the first + ::memcpy(data + 24U + 2U, data + 2U, 9U); // Copy the last audio block to the last + ::memcpy(data + 9U + 2U, data + 2U, 5U); // Copy the last audio block to the middle (1/2) + ::memcpy(data + 19U + 2U, data + 4U + 2U, 5U); // Copy the last audio block to the middle (2/2) + } else { + // Not sure what to do if this isn't AMBE audio + ::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); + } + + unsigned char n = (m_netN + 1U) % 6U; + unsigned char seqNo = m_netSeqNo + 1U; + + unsigned char fid = m_netLC->getFID(); + + CDMREMB emb; + emb.setColorCode(m_colorCode); + emb.setLCSS(0U); + + for (unsigned int i = 0U; i < count; i++) { + // Only use our silence frame if its AMBE audio data + if (fid == FID_ETSI || fid == FID_DMRA) { + if (i > 0U) { + ::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); + m_lastFrameValid = false; + } + } + + if (n == 0U) { + CSync::addDMRAudioSync(data + 2U, m_duplex); + } else { + m_netEmbeddedLC.getData(data + 2U, 0U); + emb.getData(data + 2U); + } + + writeQueueNet(data); + + m_netSeqNo = seqNo; + m_netN = n; + + m_netFrames++; + m_netLost++; + + seqNo++; + n = (n + 1U) % 6U; } } diff --git a/DMRSlot.h b/DMRSlot.h index 0a95c1a..ffe1dde 100644 --- a/DMRSlot.h +++ b/DMRSlot.h @@ -57,7 +57,7 @@ public: void clock(); - static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper); + static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter); private: unsigned int m_slotNo; @@ -78,12 +78,15 @@ private: CDMRLC* m_rfLC; CDMRLC* m_netLC; unsigned char m_rfSeqNo; + unsigned char m_netSeqNo; unsigned char m_rfN; unsigned char m_netN; CTimer m_networkWatchdog; CTimer m_rfTimeoutTimer; CTimer m_netTimeoutTimer; + CTimer m_packetTimer; CStopWatch m_interval; + CStopWatch m_elapsed; unsigned int m_rfFrames; unsigned int m_netFrames; unsigned int m_netLost; @@ -94,6 +97,8 @@ private: unsigned int m_netErrs; bool m_rfTimeout; bool m_netTimeout; + unsigned char* m_lastFrame; + bool m_lastFrameValid; unsigned char m_rssi; unsigned char m_maxRSSI; unsigned char m_minRSSI; @@ -115,6 +120,9 @@ private: static CRSSIInterpolator* m_rssiMapper; + static unsigned int m_jitterTime; + static unsigned int m_jitterSlots; + static unsigned char* m_idle; static FLCO m_flco1; @@ -138,7 +146,8 @@ private: bool writeFile(const unsigned char* data); void closeFile(); - void repeatFrame(unsigned char* data); + bool insertSilence(const unsigned char* data, unsigned char seqNo); + void insertSilence(unsigned int count); static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP, ACTIVITY_TYPE type = ACTIVITY_NONE); }; diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 85716c2..3a12efd 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -31,7 +31,7 @@ m_stopWatch(), m_buffer(NULL), m_headSequenceNumber(0U), m_lastData(NULL), -m_lastDataLength(0U) +m_lastDataValid(false) { assert(blockSize > 0U); assert(blockTime > 0U); @@ -59,11 +59,9 @@ CJitterBuffer::~CJitterBuffer() delete[] m_lastData; } -bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber) +bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumber) { assert(data != NULL); - assert(length > 0U); - assert(length <= m_blockSize); unsigned int headSequenceNumber = m_headSequenceNumber % m_topSequenceNumber; unsigned int tailSequenceNumber = (m_headSequenceNumber + m_blockCount) % m_topSequenceNumber; @@ -86,11 +84,11 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsi unsigned int index = (m_headSequenceNumber + number) % m_blockCount; // Do we already have the data? - if (m_buffer[index].m_length > 0U) + if (m_buffer[index].m_used) return false; - ::memcpy(m_buffer[index].m_data, data, length); - m_buffer[index].m_length = length; + ::memcpy(m_buffer[index].m_data, data, m_blockSize); + m_buffer[index].m_used = true; if (!m_timer.isRunning()) m_timer.start(); @@ -98,7 +96,7 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsi return true; } -JB_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length) +JB_STATUS CJitterBuffer::getData(unsigned char* data) { assert(data != NULL); @@ -113,40 +111,38 @@ JB_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length) unsigned int head = m_headSequenceNumber % m_blockCount; - m_headSequenceNumber++; - - if (m_buffer[head].m_length > 0U) { - ::memcpy(data, m_buffer[head].m_data, m_buffer[head].m_length); - length = m_buffer[head].m_length; + if (m_buffer[head].m_used) { + ::memcpy(data, m_buffer[head].m_data, m_blockSize); + m_buffer[head].m_used = false; // Save this data in case no more data is available next time - ::memcpy(m_lastData, m_buffer[head].m_data, m_buffer[head].m_length); - m_lastDataLength = m_buffer[head].m_length; + ::memcpy(m_lastData, m_buffer[head].m_data, m_blockSize); + m_lastDataValid = true; - m_buffer[head].m_length = 0U; + m_headSequenceNumber++; return JBS_DATA; } - // Return the last data frame if we have it - if (m_lastDataLength > 0U) { - ::memcpy(data, m_lastData, m_lastDataLength); - length = m_lastDataLength; + // Return the last data frame or null data if none exists + if (m_lastDataValid) + ::memcpy(data, m_lastData, m_blockSize); + else + ::memset(data, 0x00U, m_blockSize); - return JBS_MISSING; - } + m_headSequenceNumber++; - return JBS_NO_DATA; + return JBS_MISSING; } void CJitterBuffer::reset() { for (unsigned int i = 0U; i < m_blockCount; i++) - m_buffer[i].m_length = 0U; + m_buffer[i].m_used = false; m_headSequenceNumber = 0U; - m_lastDataLength = 0U; + m_lastDataValid = false; m_timer.stop(); } diff --git a/JitterBuffer.h b/JitterBuffer.h index a37339e..74fb1d8 100644 --- a/JitterBuffer.h +++ b/JitterBuffer.h @@ -33,9 +33,9 @@ public: CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber); ~CJitterBuffer(); - bool addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber); + bool addData(const unsigned char* data, unsigned int sequenceNumber); - JB_STATUS getData(unsigned char* data, unsigned int& length); + JB_STATUS getData(unsigned char* data); void reset(); @@ -52,14 +52,14 @@ private: struct JitterEntry { unsigned char* m_data; - unsigned int m_length; + bool m_used; }; JitterEntry* m_buffer; unsigned int m_headSequenceNumber; unsigned char* m_lastData; - unsigned int m_lastDataLength; + bool m_lastDataValid; }; #endif diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 4f70648..1178cbb 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -380,6 +380,7 @@ int CMMDVMHost::run() std::vector slot2TGWhiteList = m_conf.getDMRSlot2TGWhiteList(); unsigned int callHang = m_conf.getDMRCallHang(); unsigned int txHang = m_conf.getDMRTXHang(); + unsigned int jitter = m_conf.getDMRNetworkJitter(); m_dmrRFModeHang = m_conf.getDMRModeHang(); if (txHang > m_dmrRFModeHang) @@ -414,7 +415,7 @@ int CMMDVMHost::run() LogInfo(" TX Hang: %us", txHang); LogInfo(" Mode Hang: %us", m_dmrRFModeHang); - dmr = new CDMRControl(id, colorCode, callHang, selfOnly, embeddedLCOnly, dumpTAData, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_lookup, rssi); + dmr = new CDMRControl(id, colorCode, callHang, selfOnly, embeddedLCOnly, dumpTAData, prefixes, blackList, whiteList, slot1TGWhiteList, slot2TGWhiteList, m_timeout, m_modem, m_dmrNetwork, m_display, m_duplex, m_lookup, rssi, jitter); m_dmrTXTimer.setTimeout(txHang); }