From e6ed2e17a13000661296905b49d5517b510bab8b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 8 Feb 2018 20:25:03 +0000 Subject: [PATCH] Roll back the jitter buffer changes. --- Conf.cpp | 8 -- Conf.h | 2 - DMRControl.cpp | 4 +- DMRControl.h | 2 +- DMRData.cpp | 13 --- DMRData.h | 4 - DMRNetwork.cpp | 179 +++++++++-------------------- DMRNetwork.h | 14 +-- DMRSlot.cpp | 208 ++++++++++++++++++++++++++------- DMRSlot.h | 14 ++- Defines.h | 6 - DelayBuffer.cpp | 137 ---------------------- DelayBuffer.h | 57 --------- JitterBuffer.cpp | 236 -------------------------------------- JitterBuffer.h | 68 ----------- MMDVM.ini | 3 +- MMDVMHost.cpp | 7 +- MMDVMHost.vcxproj | 4 - MMDVMHost.vcxproj.filters | 12 -- Makefile | 4 +- Makefile.Pi | 4 +- Makefile.Pi.Adafruit | 4 +- Makefile.Pi.HD44780 | 4 +- Makefile.Pi.OLED | 4 +- Makefile.Pi.PCF8574 | 4 +- Makefile.Solaris | 4 +- 26 files changed, 256 insertions(+), 750 deletions(-) delete mode 100644 DelayBuffer.cpp delete mode 100644 DelayBuffer.h delete mode 100644 JitterBuffer.cpp delete mode 100644 JitterBuffer.h diff --git a/Conf.cpp b/Conf.cpp index 7483f1c..5afec64 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -153,7 +153,6 @@ m_dmrNetworkLocal(0U), m_dmrNetworkPassword(), m_dmrNetworkOptions(), m_dmrNetworkDebug(false), -m_dmrNetworkJitterEnabled(false), m_dmrNetworkJitter(300U), m_dmrNetworkSlot1(true), m_dmrNetworkSlot2(true), @@ -551,8 +550,6 @@ bool CConf::read() m_dmrNetworkOptions = value; else if (::strcmp(key, "Debug") == 0) m_dmrNetworkDebug = ::atoi(value) == 1; - else if (::strcmp(key, "JitterEnabled") == 0) - m_dmrNetworkJitterEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Jitter") == 0) m_dmrNetworkJitter = (unsigned int)::atoi(value); else if (::strcmp(key, "Slot1") == 0) @@ -1164,11 +1161,6 @@ bool CConf::getDMRNetworkDebug() const return m_dmrNetworkDebug; } -bool CConf::getDMRNetworkJitterEnabled() const -{ - return m_dmrNetworkJitterEnabled; -} - unsigned int CConf::getDMRNetworkJitter() const { return m_dmrNetworkJitter; diff --git a/Conf.h b/Conf.h index 5ef5efa..2f7304a 100644 --- a/Conf.h +++ b/Conf.h @@ -154,7 +154,6 @@ public: std::string getDMRNetworkPassword() const; std::string getDMRNetworkOptions() const; bool getDMRNetworkDebug() const; - bool getDMRNetworkJitterEnabled() const; unsigned int getDMRNetworkJitter() const; bool getDMRNetworkSlot1() const; bool getDMRNetworkSlot2() const; @@ -328,7 +327,6 @@ private: std::string m_dmrNetworkPassword; std::string m_dmrNetworkOptions; bool m_dmrNetworkDebug; - bool m_dmrNetworkJitterEnabled; unsigned int m_dmrNetworkJitter; bool m_dmrNetworkSlot1; bool m_dmrNetworkSlot2; diff --git a/DMRControl.cpp b/DMRControl.cpp index 88f58ed..a9d82e6 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 d034e6f..01179b4 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/DMRData.cpp b/DMRData.cpp index 0b50e07..25dea58 100644 --- a/DMRData.cpp +++ b/DMRData.cpp @@ -29,7 +29,6 @@ m_dstId(data.m_dstId), m_flco(data.m_flco), m_dataType(data.m_dataType), m_seqNo(data.m_seqNo), -m_missing(data.m_missing), m_n(data.m_n), m_ber(data.m_ber), m_rssi(data.m_rssi) @@ -46,7 +45,6 @@ m_dstId(0U), m_flco(FLCO_GROUP), m_dataType(0U), m_seqNo(0U), -m_missing(false), m_n(0U), m_ber(0U), m_rssi(0U) @@ -70,7 +68,6 @@ CDMRData& CDMRData::operator=(const CDMRData& data) m_flco = data.m_flco; m_dataType = data.m_dataType; m_seqNo = data.m_seqNo; - m_missing = data.m_missing; m_n = data.m_n; m_ber = data.m_ber; m_rssi = data.m_rssi; @@ -141,16 +138,6 @@ void CDMRData::setSeqNo(unsigned char seqNo) m_seqNo = seqNo; } -bool CDMRData::isMissing() const -{ - return m_missing; -} - -void CDMRData::setMissing(bool missing) -{ - m_missing = missing; -} - unsigned char CDMRData::getN() const { return m_n; diff --git a/DMRData.h b/DMRData.h index b06f416..c5dc4fc 100644 --- a/DMRData.h +++ b/DMRData.h @@ -45,9 +45,6 @@ public: unsigned char getDataType() const; void setDataType(unsigned char dataType); - bool isMissing() const; - void setMissing(bool missing); - unsigned char getBER() const; void setBER(unsigned char ber); @@ -65,7 +62,6 @@ private: FLCO m_flco; unsigned char m_dataType; unsigned char m_seqNo; - bool m_missing; unsigned char m_n; unsigned char m_ber; unsigned char m_rssi; diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index 8149019..7ec6a41 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -32,7 +32,7 @@ const unsigned int BUFFER_LENGTH = 500U; const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U; -CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, bool jitterEnabled, unsigned int jitter) : +CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) : m_address(), m_port(port), m_id(NULL), @@ -44,9 +44,6 @@ m_socket(local), m_enabled(false), m_slot1(slot1), m_slot2(slot2), -m_jitterEnabled(jitterEnabled), -m_jitterBuffers(NULL), -m_delayBuffers(NULL), m_hwType(hwType), m_status(WAITING_CONNECT), m_retryTimer(1000U, 10U), @@ -54,6 +51,7 @@ m_timeoutTimer(1000U, 60U), m_buffer(NULL), m_salt(NULL), m_streamId(NULL), +m_rxData(1000U, "DMR Network"), m_options(), m_callsign(), m_rxFrequency(0U), @@ -72,23 +70,13 @@ m_beacon(false) assert(port > 0U); assert(id > 1000U); assert(!password.empty()); - assert(jitter > 0U); m_address = CUDPSocket::lookup(address); - m_buffer = new unsigned char[BUFFER_LENGTH]; - m_salt = new unsigned char[sizeof(uint32_t)]; - m_id = new uint8_t[4U]; - m_streamId = new uint32_t[2U]; - - m_jitterBuffers = new CJitterBuffer*[3U]; - m_delayBuffers = new CDelayBuffer*[3U]; - - m_jitterBuffers[1U] = new CJitterBuffer("DMR Slot 1", 60U, DMR_SLOT_TIME, jitter, 256U, debug); - m_jitterBuffers[2U] = new CJitterBuffer("DMR Slot 2", 60U, DMR_SLOT_TIME, jitter, 256U, debug); - - m_delayBuffers[1U] = new CDelayBuffer("DMR Slot 1", HOMEBREW_DATA_PACKET_LENGTH, DMR_SLOT_TIME, jitter, debug); - m_delayBuffers[2U] = new CDelayBuffer("DMR Slot 2", HOMEBREW_DATA_PACKET_LENGTH, DMR_SLOT_TIME, jitter, debug); + m_buffer = new unsigned char[BUFFER_LENGTH]; + m_salt = new unsigned char[sizeof(uint32_t)]; + m_id = new uint8_t[4U]; + m_streamId = new uint32_t[2U]; m_id[0U] = id >> 24; m_id[1U] = id >> 16; @@ -104,19 +92,10 @@ m_beacon(false) CDMRNetwork::~CDMRNetwork() { - delete m_jitterBuffers[1U]; - delete m_jitterBuffers[2U]; - - delete m_delayBuffers[1U]; - delete m_delayBuffers[2U]; - delete[] m_buffer; delete[] m_salt; delete[] m_streamId; delete[] m_id; - - delete[] m_jitterBuffers; - delete[] m_delayBuffers; } void CDMRNetwork::setOptions(const std::string& options) @@ -160,55 +139,63 @@ bool CDMRNetwork::read(CDMRData& data) if (m_status != RUNNING) return false; - for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { - unsigned int length = 0U; - B_STATUS status = BS_NO_DATA; + if (m_rxData.isEmpty()) + return false; - if (m_jitterEnabled) - status = m_jitterBuffers[slotNo]->getData(m_buffer, length); - else - status = m_delayBuffers[slotNo]->getData(m_buffer, length); + unsigned char length = 0U; + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); - if (status != BS_NO_DATA) { - unsigned char seqNo = m_buffer[4U]; + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) != 0) + return false; - unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + unsigned char seqNo = m_buffer[4U]; - unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); - FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); - data.setSeqNo(seqNo); - data.setSlotNo(slotNo); - data.setSrcId(srcId); - data.setDstId(dstId); - data.setFLCO(flco); - data.setMissing(status == BS_MISSING); + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; - bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + // DMO mode slot disabling + if (slotNo == 1U && !m_duplex) + return false; - if (dataSync) { - unsigned char dataType = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(dataType); - data.setN(0U); - } else if (voiceSync) { - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE_SYNC); - data.setN(0U); - } else { - unsigned char n = m_buffer[15U] & 0x0FU; - data.setData(m_buffer + 20U); - data.setDataType(DT_VOICE); - data.setN(n); - } + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + return false; + if (slotNo == 2U && !m_slot2) + return false; - return true; - } + FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP; + + data.setSeqNo(seqNo); + data.setSlotNo(slotNo); + data.setSrcId(srcId); + data.setDstId(dstId); + data.setFLCO(flco); + + bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U; + bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U; + + if (dataSync) { + unsigned char dataType = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(dataType); + data.setN(0U); + } else if (voiceSync) { + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE_SYNC); + data.setN(0U); + } else { + unsigned char n = m_buffer[15U] & 0x0FU; + data.setData(m_buffer + 20U); + data.setDataType(DT_VOICE); + data.setN(n); } - return false; + return true; } bool CDMRNetwork::write(const CDMRData& data) @@ -345,12 +332,6 @@ void CDMRNetwork::close() void CDMRNetwork::clock(unsigned int ms) { - m_jitterBuffers[1U]->clock(ms); - m_jitterBuffers[2U]->clock(ms); - - m_delayBuffers[1U]->clock(ms); - m_delayBuffers[2U]->clock(ms); - if (m_status == WAITING_CONNECT) { m_retryTimer.clock(ms); if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { @@ -388,7 +369,10 @@ void CDMRNetwork::clock(unsigned int ms) if (m_enabled) { if (m_debug) CUtils::dump(1U, "Network Received", m_buffer, length); - receiveData(m_buffer, length); + + unsigned char len = length; + m_rxData.addData(&len, 1U); + m_rxData.addData(m_buffer, len); } } else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) { if (m_status == RUNNING) { @@ -489,57 +473,6 @@ void CDMRNetwork::clock(unsigned int ms) } } -void CDMRNetwork::reset(unsigned int slotNo) -{ - assert(slotNo == 1U || slotNo == 2U); - - if (slotNo == 1U) { - m_jitterBuffers[1U]->reset(); - m_delayBuffers[1U]->reset(); - m_streamId[0U] = ::rand() + 1U; - } else { - m_jitterBuffers[2U]->reset(); - m_delayBuffers[2U]->reset(); - m_streamId[1U] = ::rand() + 1U; - } -} - -void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - - unsigned int slotNo = (data[15U] & 0x80U) == 0x80U ? 2U : 1U; - - // DMO mode slot disabling - if (slotNo == 1U && !m_duplex) - return; - - // Individual slot disabling - if (slotNo == 1U && !m_slot1) - return; - if (slotNo == 2U && !m_slot2) - return; - - if (m_jitterEnabled) { - unsigned char dataType = data[15U] & 0x3FU; - if (dataType == (0x20U | DT_CSBK) || - dataType == (0x20U | DT_DATA_HEADER) || - dataType == (0x20U | DT_RATE_1_DATA) || - dataType == (0x20U | DT_RATE_34_DATA) || - dataType == (0x20U | DT_RATE_12_DATA)) { - // Data & CSBK frames - m_jitterBuffers[slotNo]->appendData(data, length); - } else { - // Voice frames - unsigned char seqNo = data[4U]; - m_jitterBuffers[slotNo]->addData(data, length, seqNo); - } - } else { - m_delayBuffers[slotNo]->addData(data, length); - } -} - bool CDMRNetwork::writeLogin() { unsigned char buffer[8U]; diff --git a/DMRNetwork.h b/DMRNetwork.h index 799b2bc..d1d12e4 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -19,10 +19,9 @@ #if !defined(DMRNetwork_H) #define DMRNetwork_H -#include "JitterBuffer.h" -#include "DelayBuffer.h" #include "UDPSocket.h" #include "Timer.h" +#include "RingBuffer.h" #include "DMRData.h" #include "Defines.h" @@ -32,7 +31,7 @@ class CDMRNetwork { public: - CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, bool jitterEnabled, unsigned int jitter); + CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType); ~CDMRNetwork(); void setOptions(const std::string& options); @@ -55,8 +54,6 @@ public: void clock(unsigned int ms); - void reset(unsigned int slotNo); - void close(); private: @@ -71,9 +68,6 @@ private: bool m_enabled; bool m_slot1; bool m_slot2; - bool m_jitterEnabled; - CJitterBuffer** m_jitterBuffers; - CDelayBuffer** m_delayBuffers; HW_TYPE m_hwType; enum STATUS { @@ -92,6 +86,8 @@ private: unsigned char* m_salt; uint32_t* m_streamId; + CRingBuffer m_rxData; + std::string m_options; std::string m_callsign; @@ -115,8 +111,6 @@ private: bool writePing(); bool write(const unsigned char* data, unsigned int length); - - void receiveData(const unsigned char* data, unsigned int length); }; #endif diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 7db9c53..f0dbd2c 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,16 +87,18 @@ 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), -m_netMissed(0U), m_fec(), m_rfBits(1U), m_netBits(1U), @@ -101,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), @@ -110,6 +117,8 @@ 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]; @@ -120,6 +129,7 @@ CDMRSlot::~CDMRSlot() { delete[] m_rfEmbeddedData; delete[] m_netEmbeddedData; + delete[] m_lastFrame; delete[] m_rfTalkerAlias; } @@ -900,9 +910,6 @@ void CDMRSlot::writeEndRF(bool writeEnd) } } - if (m_network != NULL) - m_network->reset(m_slotNo); - m_rfTimeoutTimer.stop(); m_rfTimeout = false; @@ -925,6 +932,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]; @@ -951,11 +960,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; @@ -979,22 +986,13 @@ 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); - bool missing = dmrData.isMissing(); - - unsigned char dataType; - if (missing) { - m_netN = (m_netN + 1U) % 6U; - dataType = repeatFrame(data + 2U); - } else { - dataType = dmrData.getDataType(); - m_netN = dmrData.getN(); - m_networkWatchdog.start(); - m_netMissed = 0U; - } - if (dataType == DT_VOICE_LC_HEADER) { if (m_netState == RS_NET_AUDIO) return; @@ -1037,6 +1035,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; data[1U] = 0x00U; + m_lastFrameValid = false; + m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1054,6 +1054,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); @@ -1085,6 +1088,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netLC = lc; + m_lastFrameValid = false; + m_netTimeoutTimer.start(); m_netTimeout = false; @@ -1093,6 +1098,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]; @@ -1231,6 +1239,10 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = m_netFrames == 0U ? TAG_EOT : TAG_DATA; data[1U] = 0x00U; + // Put a small delay into starting transmission + writeQueueNet(m_idle); + writeQueueNet(m_idle); + writeQueueNet(data); m_netState = RS_NET_DATA; @@ -1262,6 +1274,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; @@ -1270,6 +1284,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]; @@ -1330,6 +1347,17 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Convert the Audio Sync to be from the BS or MS as needed 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(); + m_netLost = 0U; + } else { + insertSilence(data, dmrData.getSeqNo()); + } + if (!m_netTimeout) writeQueueNet(data); @@ -1338,11 +1366,15 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_netEmbeddedData[m_netEmbeddedWriteN].reset(); - if (missing) - m_netLost++; + 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 @@ -1469,14 +1501,29 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) data[0U] = TAG_DATA; 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(); + m_netLost = 0U; + } else { + insertSilence(data, dmrData.getSeqNo()); + } + if (!m_netTimeout) writeQueueNet(data); - if (missing) - m_netLost++; + 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 @@ -1687,6 +1734,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) @@ -1760,7 +1822,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); @@ -1779,6 +1841,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); @@ -1924,33 +1989,88 @@ void CDMRSlot::closeFile() } } -unsigned char CDMRSlot::repeatFrame(unsigned char* data) +bool CDMRSlot::insertSilence(const unsigned char* data, unsigned char seqNo) { - // Repeat the last audio for 60ms then silence after that - if (m_netMissed == 0U) { - ::memcpy(data, data + 24U, 9U); // Copy the last audio block to the first - ::memcpy(data + 9U, data + 24U, 5U); // Copy the last audio block to the middle (1/2) - ::memcpy(data + 19U, data + 24U, 5U); // Copy the last audio block to the middle (2/2) - } else { - ::memcpy(data, DMR_SILENCE_DATA + 2U, DMR_FRAME_LENGTH_BYTES); + 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; } - if (m_netN == 0U) { - CSync::addDMRAudioSync(data, m_duplex); + unsigned int oldSeqNo = m_netSeqNo + 1U; + unsigned int newSeqNo = seqNo; - m_netMissed++; + unsigned int count; + if (newSeqNo > oldSeqNo) + count = newSeqNo - oldSeqNo; + else + count = (256U + newSeqNo) - oldSeqNo; - return DT_VOICE_SYNC; + 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 { - m_netEmbeddedLC.getData(data, 0U); + // Not sure what to do if this isn't AMBE audio + ::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U); + } - CDMREMB emb; - emb.setColorCode(m_colorCode); - emb.setLCSS(0U); - emb.getData(data); + unsigned char n = (m_netN + 1U) % 6U; + unsigned char seqNo = m_netSeqNo + 1U; - m_netMissed++; + unsigned char fid = m_netLC->getFID(); - return DT_VOICE; + 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 daf835d..e2df1a4 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,16 +78,18 @@ 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; - unsigned int m_netMissed; CAMBEFEC m_fec; unsigned int m_rfBits; unsigned int m_netBits; @@ -95,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; @@ -116,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; @@ -139,7 +146,8 @@ private: bool writeFile(const unsigned char* data); void closeFile(); - unsigned char 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/Defines.h b/Defines.h index 852fd3e..a82266b 100644 --- a/Defines.h +++ b/Defines.h @@ -57,10 +57,4 @@ enum RPT_NET_STATE { RS_NET_DATA }; -enum B_STATUS { - BS_NO_DATA, - BS_DATA, - BS_MISSING -}; - #endif diff --git a/DelayBuffer.cpp b/DelayBuffer.cpp deleted file mode 100644 index e38125b..0000000 --- a/DelayBuffer.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* -* Copyright (C) 2018 by Jonathan Naylor G4KLX -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "DelayBuffer.h" - -#include "Log.h" - -#include -#include -#include - -CDelayBuffer::CDelayBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, bool debug) : -m_name(name), -m_blockSize(blockSize), -m_blockTime(blockTime), -m_debug(debug), -m_timer(1000U, 0U, jitterTime), -m_stopWatch(), -m_running(false), -m_buffer(1000U, name.c_str()), -m_outputCount(0U), -m_lastData(NULL), -m_lastDataLength(0U) -{ - assert(blockSize > 0U); - assert(blockTime > 0U); - assert(jitterTime > 0U); - - m_lastData = new unsigned char[m_blockSize]; - - reset(); -} - -CDelayBuffer::~CDelayBuffer() -{ - delete[] m_lastData; -} - -bool CDelayBuffer::addData(const unsigned char* data, unsigned int length) -{ - assert(data != NULL); - assert(length > 0U); - assert(length == m_blockSize); - - if (m_debug) - LogDebug("%s, DelayBuffer: appending data", m_name.c_str()); - - m_buffer.addData(data, length); - - if (!m_timer.isRunning()) { - LogDebug("%s, DelayBuffer: starting the timer from append", m_name.c_str()); - m_timer.start(); - } - - return true; -} - -B_STATUS CDelayBuffer::getData(unsigned char* data, unsigned int& length) -{ - assert(data != NULL); - - if (!m_running) - return BS_NO_DATA; - - unsigned int needed = m_stopWatch.elapsed() / m_blockTime + 2U; - if (needed <= m_outputCount) - return BS_NO_DATA; - - if (!m_buffer.isEmpty()) { - if (m_debug) - LogDebug("%s, DelayBuffer: returning data, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed()); - - length = m_buffer.getData(data, m_blockSize); - - // Save this data in case no more data is available next time - ::memcpy(m_lastData, data, length); - m_lastDataLength = length; - - m_outputCount++; - - return BS_DATA; - } - - LogDebug("%s, DelayBuffer: no data available, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed()); - - // Return the last data frame if we have it - if (m_lastDataLength > 0U) { - LogDebug("%s, DelayBuffer: returning the last received frame", m_name.c_str()); - ::memcpy(data, m_lastData, m_lastDataLength); - length = m_lastDataLength; - - m_outputCount++; - - return BS_MISSING; - } - - return BS_NO_DATA; -} - -void CDelayBuffer::reset() -{ - m_buffer.clear(); - - m_lastDataLength = 0U; - - m_outputCount = 0U; - - m_timer.stop(); - - m_running = false; -} - -void CDelayBuffer::clock(unsigned int ms) -{ - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - if (!m_running) { - m_stopWatch.start(); - m_running = true; - } - } -} diff --git a/DelayBuffer.h b/DelayBuffer.h deleted file mode 100644 index d773f26..0000000 --- a/DelayBuffer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* Copyright (C) 2018 by Jonathan Naylor G4KLX -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#if !defined(DELAYBUFFER_H) -#define DELAYBUFFER_H - -#include "RingBuffer.h" -#include "StopWatch.h" -#include "Defines.h" -#include "Timer.h" - -#include - -class CDelayBuffer { -public: - CDelayBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, bool debug); - ~CDelayBuffer(); - - bool addData(const unsigned char* data, unsigned int length); - - B_STATUS getData(unsigned char* data, unsigned int& length); - - void reset(); - - void clock(unsigned int ms); - -private: - std::string m_name; - unsigned int m_blockSize; - unsigned int m_blockTime; - bool m_debug; - CTimer m_timer; - CStopWatch m_stopWatch; - bool m_running; - CRingBuffer m_buffer; - unsigned int m_outputCount; - - unsigned char* m_lastData; - unsigned int m_lastDataLength; -}; - -#endif diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp deleted file mode 100644 index 3af4f48..0000000 --- a/JitterBuffer.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* -* Copyright (C) 2017,2018 by Jonathan Naylor G4KLX -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "JitterBuffer.h" - -#include "Log.h" - -#include -#include -#include - -CJitterBuffer::CJitterBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug) : -m_name(name), -m_blockSize(blockSize), -m_blockTime(blockTime), -m_topSequenceNumber(topSequenceNumber), -m_debug(debug), -m_blockCount(0U), -m_timer(1000U, 0U, jitterTime), -m_stopWatch(), -m_running(false), -m_buffer(NULL), -m_headSequenceNumber(0U), -m_appendSequenceNumber(0U), -m_lastData(NULL), -m_lastDataLength(0U) -{ - assert(blockSize > 0U); - assert(blockTime > 0U); - assert(jitterTime > 0U); - assert(topSequenceNumber > 0U); - - m_blockCount = topSequenceNumber / 2U; - - m_buffer = new JitterEntry[m_blockCount]; - - for (unsigned int i = 0U; i < m_blockCount; i++) - m_buffer[i].m_data = new unsigned char[m_blockSize]; - - m_lastData = new unsigned char[m_blockSize]; - - reset(); -} - -CJitterBuffer::~CJitterBuffer() -{ - for (unsigned int i = 0U; i < m_blockCount; i++) - delete[] m_buffer[i].m_data; - - delete[] m_buffer; - delete[] m_lastData; -} - -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; - - // Is the data out of sequence? - if (headSequenceNumber < tailSequenceNumber) { - if (sequenceNumber < headSequenceNumber || sequenceNumber >= tailSequenceNumber) { - LogDebug("%s, JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - return false; - } - } else { - if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) { - LogDebug("%s, JitterBuffer: rejecting frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - return false; - } - } - - unsigned int number; - if (sequenceNumber >= headSequenceNumber) - number = sequenceNumber - headSequenceNumber; - else - number = (sequenceNumber + m_blockCount) - headSequenceNumber;; - - unsigned int index = (m_headSequenceNumber + number) % m_blockCount; - - // Do we already have the data? - if (m_buffer[index].m_length > 0U) { - LogDebug("%s, JitterBuffer: rejecting duplicate frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - return false; - } - - if (m_debug) - LogDebug("%s, JitterBuffer: adding frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), sequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - - ::memcpy(m_buffer[index].m_data, data, length); - m_buffer[index].m_length = length; - - if (!m_timer.isRunning()) { - LogDebug("%s, JitterBuffer: starting the timer", m_name.c_str()); - m_timer.start(); - } - - return true; -} - -bool CJitterBuffer::appendData(const unsigned char* data, unsigned int length) -{ - 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; - - // Is the data out of sequence? - if (headSequenceNumber < tailSequenceNumber) { - if (m_appendSequenceNumber < headSequenceNumber || m_appendSequenceNumber >= tailSequenceNumber) { - LogDebug("%s, JitterBuffer: rejecting append frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - return false; - } - } else { - if (m_appendSequenceNumber >= tailSequenceNumber && m_appendSequenceNumber < headSequenceNumber) { - LogDebug("%s, JitterBuffer: rejecting append frame with seqNo=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - return false; - } - } - - unsigned int number; - if (m_appendSequenceNumber >= headSequenceNumber) - number = m_appendSequenceNumber - headSequenceNumber; - else - number = (m_appendSequenceNumber + m_blockCount) - headSequenceNumber;; - - unsigned int index = (m_headSequenceNumber + number) % m_blockCount; - - if (m_debug) - LogDebug("%s, JitterBuffer: appending frame with seqNo=%u, pos=%u, raw=%u, head=%u, tail=%u", m_name.c_str(), m_appendSequenceNumber, index, m_headSequenceNumber, headSequenceNumber, tailSequenceNumber); - - ::memcpy(m_buffer[index].m_data, data, length); - m_buffer[index].m_length = length; - - if (!m_timer.isRunning()) { - LogDebug("%s, JitterBuffer: starting the timer from append", m_name.c_str()); - m_timer.start(); - } - - m_appendSequenceNumber++; - - return true; -} - -B_STATUS CJitterBuffer::getData(unsigned char* data, unsigned int& length) -{ - assert(data != NULL); - - if (!m_running) - return BS_NO_DATA; - - unsigned int sequenceNumber = m_stopWatch.elapsed() / m_blockTime + 2U; - if (m_headSequenceNumber > sequenceNumber) - return BS_NO_DATA; - - unsigned int head = m_headSequenceNumber % m_blockCount; - - m_headSequenceNumber++; - - if (m_buffer[head].m_length > 0U) { - if (m_debug) - LogDebug("%s, JitterBuffer: returning data, elapsed=%ums, raw=%u, head=%u", m_name.c_str(), m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head); - - ::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_buffer[head].m_length); - m_lastDataLength = m_buffer[head].m_length; - - m_buffer[head].m_length = 0U; - - return BS_DATA; - } - - m_buffer[head].m_length = 0U; - - LogDebug("%s, JitterBuffer: no data available, elapsed=%ums, raw=%u, head=%u", m_name.c_str(), m_stopWatch.elapsed(), m_headSequenceNumber - 1U, head); - - // Return the last data frame if we have it - if (m_lastDataLength > 0U) { - LogDebug("%s, JitterBuffer: returning the last received frame", m_name.c_str()); - ::memcpy(data, m_lastData, m_lastDataLength); - length = m_lastDataLength; - - return BS_MISSING; - } - - return BS_NO_DATA; -} - -void CJitterBuffer::reset() -{ - for (unsigned int i = 0U; i < m_blockCount; i++) - m_buffer[i].m_length = 0U; - - m_headSequenceNumber = 0U; - m_appendSequenceNumber = 0U; - - m_lastDataLength = 0U; - - m_timer.stop(); - - m_running = false; -} - -void CJitterBuffer::clock(unsigned int ms) -{ - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - if (!m_running) { - m_stopWatch.start(); - m_running = true; - } - } -} diff --git a/JitterBuffer.h b/JitterBuffer.h deleted file mode 100644 index 9a9f1fe..0000000 --- a/JitterBuffer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -* Copyright (C) 2017,2018 by Jonathan Naylor G4KLX -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#if !defined(JITTERBUFFER_H) -#define JITTERBUFFER_H - -#include "StopWatch.h" -#include "Defines.h" -#include "Timer.h" - -#include - -class CJitterBuffer { -public: - CJitterBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber, bool debug); - ~CJitterBuffer(); - - bool addData(const unsigned char* data, unsigned int length, unsigned int sequenceNumber); - bool appendData(const unsigned char* data, unsigned int length); - - B_STATUS getData(unsigned char* data, unsigned int& length); - - void reset(); - - void clock(unsigned int ms); - -private: - std::string m_name; - unsigned int m_blockSize; - unsigned int m_blockTime; - unsigned int m_topSequenceNumber; - bool m_debug; - unsigned int m_blockCount; - CTimer m_timer; - CStopWatch m_stopWatch; - bool m_running; - - struct JitterEntry - { - unsigned char* m_data; - unsigned int m_length; - }; - - JitterEntry* m_buffer; - unsigned int m_headSequenceNumber; - - unsigned int m_appendSequenceNumber; - - unsigned char* m_lastData; - unsigned int m_lastDataLength; -}; - -#endif diff --git a/MMDVM.ini b/MMDVM.ini index 75818a8..6f0ce32 100644 --- a/MMDVM.ini +++ b/MMDVM.ini @@ -119,8 +119,7 @@ Debug=0 Enable=1 Address=44.131.4.1 Port=62031 -JitterEnabled=0 -Jitter=500 +Jitter=300 # Local=62032 Password=PASSWORD # Options= diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 754c49f..e2b7ed6 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(); bool dmrBeacons = m_conf.getDMRBeacons(); @@ -428,7 +429,7 @@ int CMMDVMHost::run() dmrBeaconIntervalTimer.start(); } - 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); } @@ -944,7 +945,6 @@ bool CMMDVMHost::createDMRNetwork() unsigned int id = m_conf.getDMRId(); std::string password = m_conf.getDMRNetworkPassword(); bool debug = m_conf.getDMRNetworkDebug(); - bool jitterEnabled = m_conf.getDMRNetworkJitterEnabled(); unsigned int jitter = m_conf.getDMRNetworkJitter(); bool slot1 = m_conf.getDMRNetworkSlot1(); bool slot2 = m_conf.getDMRNetworkSlot2(); @@ -958,13 +958,12 @@ bool CMMDVMHost::createDMRNetwork() LogInfo(" Local: %u", local); else LogInfo(" Local: random"); - LogInfo(" Jitter Buffer: %s", jitterEnabled ? "enabled" : "disabled"); LogInfo(" Jitter: %ums", jitter); LogInfo(" Slot 1: %s", slot1 ? "enabled" : "disabled"); LogInfo(" Slot 2: %s", slot2 ? "enabled" : "disabled"); LogInfo(" Mode Hang: %us", m_dmrNetModeHang); - m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType, jitterEnabled, jitter); + m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType); std::string options = m_conf.getDMRNetworkOptions(); if (!options.empty()) { diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index b5b8162..0f61416 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -158,7 +158,6 @@ - @@ -184,7 +183,6 @@ - @@ -233,7 +231,6 @@ - @@ -257,7 +254,6 @@ - diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 6f28b05..f27a2da 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -224,15 +224,9 @@ Header Files - - Header Files - Header Files - - Header Files - @@ -427,14 +421,8 @@ Source Files - - Source Files - Source Files - - Source Files - \ No newline at end of file diff --git a/Makefile b/Makefile index 43c1476..1b4efd4 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ LIBS = -lpthread LDFLAGS = -g OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi b/Makefile.Pi index 22fc628..fdf2cd8 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -7,9 +7,9 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 390d07d..2602e1c 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -7,9 +7,9 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index ae7266e..401e161 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -7,9 +7,9 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index ff61b18..5d61cc9 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -7,9 +7,9 @@ LIBS = -lArduiPi_OLED -li2c -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o JitterBuffer.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o OLED.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 5aea72c..4006e96 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -7,9 +7,9 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread LDFLAGS = -g -L/usr/local/lib OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o HD44780.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o \ Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o diff --git a/Makefile.Solaris b/Makefile.Solaris index 4c47f85..e86d7f5 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -7,9 +7,9 @@ LIBS = -lpthread -lsocket LDFLAGS = -g OBJECTS = \ - AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o DelayBuffer.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ + AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedData.o DMRFullLC.o \ DMRLookup.o DMRLC.o DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o \ - DStarSlowData.o Golay2087.o Golay24128.o Hamming.o JitterBuffer.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ + DStarSlowData.o Golay2087.o Golay24128.o Hamming.o LCDproc.o Log.o MMDVMHost.o Modem.o ModemSerialPort.o Mutex.o NetworkInfo.o Nextion.o \ NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Trellis.o P25Utils.o QR1676.o RS129.o RS241213.o \ RSSIInterpolator.o SerialController.o SerialPort.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o UMP.o Utils.o YSFControl.o \ YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o