From e1800c0fe03f470475f1daba1a284cf898868e94 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 13:18:37 +0000 Subject: [PATCH] Full integration of the jitter buffer into DMR. --- DMRControl.cpp | 4 +- DMRControl.h | 2 +- DMRNetwork.cpp | 5 +- DMRSlot.cpp | 189 +++++++---------------------------------------- DMRSlot.h | 13 +--- JitterBuffer.cpp | 46 ++++++------ JitterBuffer.h | 8 +- MMDVMHost.cpp | 3 +- 8 files changed, 66 insertions(+), 204 deletions(-) diff --git a/DMRControl.cpp b/DMRControl.cpp index 4d7c668..b0ef7f2 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, unsigned int jitter) : +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) : 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, jitter); + CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi); } CDMRControl::~CDMRControl() diff --git a/DMRControl.h b/DMRControl.h index 7b7b17c..22a28c4 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, unsigned int jitter); + 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(); bool processWakeup(const unsigned char* data); diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index e840cdd..4ff02f4 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -172,13 +172,14 @@ bool CDMRNetwork::read(CDMRData& data) if (wanted) { unsigned char seqNo = m_buffer[4U]; - m_jitterBuffers[slotNo]->addData(m_buffer, seqNo); + m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); } } } for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { - JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer); + unsigned int length = 0U; + JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer, length); if (status != JBS_NO_DATA) { unsigned char seqNo = m_buffer[4U]; diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 1366d78..9925721 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -44,9 +44,6 @@ 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; @@ -86,15 +83,12 @@ 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), @@ -105,8 +99,6 @@ 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), @@ -115,7 +107,6 @@ 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]; @@ -127,7 +118,6 @@ CDMRSlot::~CDMRSlot() { delete[] m_rfEmbeddedData; delete[] m_netEmbeddedData; - delete[] m_lastFrame; delete[] m_rfTalkerAlias; } @@ -906,6 +896,9 @@ void CDMRSlot::writeEndRF(bool writeEnd) } } + if (m_network != NULL) + m_network->reset(m_slotNo); + m_rfTimeoutTimer.stop(); m_rfTimeout = false; @@ -925,8 +918,6 @@ 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]; @@ -953,9 +944,11 @@ 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; @@ -977,13 +970,20 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) if (m_rfState != RS_RF_LISTENING && m_netState == RS_NET_IDLE) return; - m_networkWatchdog.start(); - - unsigned char dataType = dmrData.getDataType(); - 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(); + } + + unsigned char dataType = dmrData.getDataType(); + if (dataType == DT_VOICE_LC_HEADER) { if (m_netState == RS_NET_AUDIO) return; @@ -1026,8 +1026,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; - m_lastFrameValid = false; - m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1045,9 +1043,6 @@ 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); @@ -1079,8 +1074,6 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netLC = lc; - m_lastFrameValid = false; - m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1089,9 +1082,6 @@ 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]; @@ -1265,8 +1255,6 @@ 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; @@ -1275,9 +1263,6 @@ 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]; @@ -1339,15 +1324,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) CSync::addDMRAudioSync(data + 2U, m_duplex); // Initialise the lost packet data - if (m_netFrames == 0U) { - ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); - m_lastFrameValid = true; - m_netSeqNo = dmrData.getSeqNo(); - m_netN = dmrData.getN(); + if (m_netFrames == 0U) m_netLost = 0U; - } else { - insertSilence(data, dmrData.getSeqNo()); - } if (!m_netTimeout) writeQueueNet(data); @@ -1357,15 +1335,8 @@ 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 @@ -1493,28 +1464,14 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[1U] = 0x00U; // Initialise the lost packet data - if (m_netFrames == 0U) { - ::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U); - m_lastFrameValid = true; - m_netSeqNo = dmrData.getSeqNo(); - m_netN = dmrData.getN(); + if (m_netFrames == 0U) 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 @@ -1726,21 +1683,6 @@ 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) @@ -1814,7 +1756,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, unsigned int jitter) +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) { assert(modem != NULL); assert(display != NULL); @@ -1833,9 +1775,6 @@ 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); @@ -1981,88 +1920,16 @@ void CDMRSlot::closeFile() } } -bool CDMRSlot::insertSilence(const unsigned char* data, unsigned char seqNo) +void CDMRSlot::repeatFrame(unsigned char* data) { - assert(data != NULL); - - // 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) + if (m_netN == 0U) { + CSync::addDMRAudioSync(data, m_duplex); } else { - // Not sure what to do if this isn't AMBE audio - ::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); - } + m_netEmbeddedLC.getData(data, 0U); - 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; + CDMREMB emb; + emb.setColorCode(m_colorCode); + emb.setLCSS(0U); + emb.getData(data); } } diff --git a/DMRSlot.h b/DMRSlot.h index 38e4a5b..fb0a616 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, unsigned int jitter); + 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); private: unsigned int m_slotNo; @@ -78,15 +78,12 @@ 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; @@ -97,8 +94,6 @@ 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; @@ -120,9 +115,6 @@ private: static CRSSIInterpolator* m_rssiMapper; - static unsigned int m_jitterTime; - static unsigned int m_jitterSlots; - static unsigned char* m_idle; static FLCO m_flco1; @@ -146,8 +138,7 @@ private: bool writeFile(const unsigned char* data); void closeFile(); - bool insertSilence(const unsigned char* data, unsigned char seqNo); - void insertSilence(unsigned int count); + void repeatFrame(unsigned char* data); 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 3a12efd..85716c2 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -31,7 +31,7 @@ m_stopWatch(), m_buffer(NULL), m_headSequenceNumber(0U), m_lastData(NULL), -m_lastDataValid(false) +m_lastDataLength(0U) { assert(blockSize > 0U); assert(blockTime > 0U); @@ -59,9 +59,11 @@ CJitterBuffer::~CJitterBuffer() delete[] m_lastData; } -bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumber) +bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, 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; @@ -84,11 +86,11 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumb unsigned int index = (m_headSequenceNumber + number) % m_blockCount; // Do we already have the data? - if (m_buffer[index].m_used) + if (m_buffer[index].m_length > 0U) return false; - ::memcpy(m_buffer[index].m_data, data, m_blockSize); - m_buffer[index].m_used = true; + ::memcpy(m_buffer[index].m_data, data, length); + m_buffer[index].m_length = length; if (!m_timer.isRunning()) m_timer.start(); @@ -96,7 +98,7 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumb return true; } -JB_STATUS CJitterBuffer::getData(unsigned char* data) +JB_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length) { assert(data != NULL); @@ -111,38 +113,40 @@ JB_STATUS CJitterBuffer::getData(unsigned char* data) unsigned int head = m_headSequenceNumber % m_blockCount; - if (m_buffer[head].m_used) { - ::memcpy(data, m_buffer[head].m_data, m_blockSize); - m_buffer[head].m_used = false; + 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; // Save this data in case no more data is available next time - ::memcpy(m_lastData, m_buffer[head].m_data, m_blockSize); - m_lastDataValid = true; + ::memcpy(m_lastData, m_buffer[head].m_data, m_buffer[head].m_length); + m_lastDataLength = m_buffer[head].m_length; - m_headSequenceNumber++; + m_buffer[head].m_length = 0U; return JBS_DATA; } - // 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 the last data frame if we have it + if (m_lastDataLength > 0U) { + ::memcpy(data, m_lastData, m_lastDataLength); + length = m_lastDataLength; - m_headSequenceNumber++; + return JBS_MISSING; + } - return JBS_MISSING; + return JBS_NO_DATA; } void CJitterBuffer::reset() { for (unsigned int i = 0U; i < m_blockCount; i++) - m_buffer[i].m_used = false; + m_buffer[i].m_length = 0U; m_headSequenceNumber = 0U; - m_lastDataValid = false; + m_lastDataLength = 0U; m_timer.stop(); } diff --git a/JitterBuffer.h b/JitterBuffer.h index 74fb1d8..a37339e 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 sequenceNumber); + bool addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber); - JB_STATUS getData(unsigned char* data); + JB_STATUS getData(unsigned char* data, unsigned int& length); void reset(); @@ -52,14 +52,14 @@ private: struct JitterEntry { unsigned char* m_data; - bool m_used; + unsigned int m_length; }; JitterEntry* m_buffer; unsigned int m_headSequenceNumber; unsigned char* m_lastData; - bool m_lastDataValid; + unsigned int m_lastDataLength; }; #endif diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 1178cbb..4f70648 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -380,7 +380,6 @@ 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) @@ -415,7 +414,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, jitter); + 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); m_dmrTXTimer.setTimeout(txHang); }