From 036d8b3d2d095cb67c9afff3f201b4233ed53f4a Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 22 Nov 2017 13:21:48 +0000 Subject: [PATCH 01/11] Beginnings of a generic jitter buffer for all modes. --- JitterBuffer.cpp | 127 ++++++++++++++++++++++++++++++++++++++ JitterBuffer.h | 62 +++++++++++++++++++ MMDVMHost.vcxproj | 2 + MMDVMHost.vcxproj.filters | 6 ++ Makefile | 6 +- Makefile.Pi | 6 +- Makefile.Pi.Adafruit | 6 +- Makefile.Pi.HD44780 | 6 +- Makefile.Pi.OLED | 6 +- Makefile.Pi.PCF8574 | 6 +- Makefile.Solaris | 6 +- 11 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 JitterBuffer.cpp create mode 100644 JitterBuffer.h diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp new file mode 100644 index 0000000..17d6cc5 --- /dev/null +++ b/JitterBuffer.cpp @@ -0,0 +1,127 @@ +/* +* Copyright (C) 2017 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 +#include + +CJitterBuffer::CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber) : +m_blockSize(blockSize), +m_blockTime(blockTime), +m_topSequenceNumber(topSequenceNumber), +m_blockCount(0U), +m_timer(1000U, 0U, jitterTime), +m_stopWatch(), +m_buffer(NULL), +m_headSequenceNumber(0U) +{ + assert(blockSize > 0U); + assert(blockTime > 0U); + assert(jitterTime > 0U); + assert(topSequenceNumber > 0U); + + m_blockCount = jitterTime / blockTime + 1U; + + 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]; + + reset(); +} + +CJitterBuffer::~CJitterBuffer() +{ + for (unsigned int i = 0U; i < m_blockCount; i++) + delete[] m_buffer[i].m_data; + + delete[] m_buffer; +} + +bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumber) +{ + assert(data != NULL); + + 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) + return false; + } else { + if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) + return false; + } + + unsigned int number = sequenceNumber - headSequenceNumber; + + // Do we already have the data? + if (m_buffer[number].m_used) + return false; + + ::memcpy(m_buffer[number].m_data, data, m_blockSize); + m_buffer[number].m_used = true; + + if (!m_timer.isRunning()) + m_timer.start(); + + return true; +} + +JB_STATUS CJitterBuffer::getData(unsigned char* data) +{ + assert(data != NULL); + + if (!m_timer.isRunning() || !m_timer.hasExpired()) { + m_stopWatch.start(); + return JBS_NO_DATA; + } + + unsigned int sequenceNumber = m_stopWatch.elapsed() / m_blockTime; + if (m_headSequenceNumber > sequenceNumber) + return JBS_NO_DATA; + + if (m_buffer[m_headSequenceNumber].m_used) { + ::memcpy(data, m_buffer[m_headSequenceNumber].m_data, m_blockSize); + + m_headSequenceNumber++; + + return JBS_DATA; + } + + m_headSequenceNumber++; + + return JBS_REPEAT; +} + +void CJitterBuffer::reset() +{ + for (unsigned int i = 0U; i < m_blockCount; i++) + m_buffer[i].m_used = false; + + m_headSequenceNumber = 0U; + + m_timer.stop(); +} + +void CJitterBuffer::clock(unsigned int ms) +{ + m_timer.clock(ms); +} diff --git a/JitterBuffer.h b/JitterBuffer.h new file mode 100644 index 0000000..951e8c0 --- /dev/null +++ b/JitterBuffer.h @@ -0,0 +1,62 @@ +/* +* Copyright (C) 2017 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 "Timer.h" + +enum JB_STATUS { + JBS_NO_DATA, + JBS_DATA, + JBS_REPEAT +}; + +class CJitterBuffer { +public: + CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber); + ~CJitterBuffer(); + + bool addData(const unsigned char* data, unsigned int sequenceNumber); + + JB_STATUS getData(unsigned char* data); + + void reset(); + + void clock(unsigned int ms); + +private: + unsigned int m_blockSize; + unsigned int m_blockTime; + unsigned int m_topSequenceNumber; + unsigned int m_blockCount; + CTimer m_timer; + CStopWatch m_stopWatch; + + struct JitterEntry + { + unsigned char* m_data; + bool m_used; + }; + + JitterEntry* m_buffer; + unsigned int m_headSequenceNumber; +}; + +#endif diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 5d575e0..2ca0a02 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -183,6 +183,7 @@ + @@ -253,6 +254,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 6373a8c..7fb37a0 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -224,6 +224,9 @@ Header Files + + Header Files + @@ -418,5 +421,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index f963f70..ee54b3e 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,9 @@ LDFLAGS = -g OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Pi b/Makefile.Pi index f7b91cc..cfe8074 100644 --- a/Makefile.Pi +++ b/Makefile.Pi @@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 13caba4..707c362 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o HD44780.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 3720b25..857c941 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o HD44780.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index bb03e91..89731ae 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index b9104f4..56c7d34 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -9,9 +9,9 @@ LDFLAGS = -g -L/usr/local/lib OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o HD44780.o JitterBuffer.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 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 all: MMDVMHost diff --git a/Makefile.Solaris b/Makefile.Solaris index dbfc33f..ad14d09 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -9,9 +9,9 @@ LDFLAGS = -g OBJECTS = \ 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 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 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 + Golay24128.o Hamming.o JitterBuffer.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 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 all: MMDVMHost From 982b0992b3171fc6a6ddfd493cc80a5496971b7f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 22 Nov 2017 13:41:10 +0000 Subject: [PATCH 02/11] Add more detail. --- JitterBuffer.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 17d6cc5..eed5822 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -60,7 +60,7 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumb 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) @@ -70,14 +70,20 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumb return false; } - unsigned int number = sequenceNumber - headSequenceNumber; + 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[number].m_used) + if (m_buffer[index].m_used) return false; - ::memcpy(m_buffer[number].m_data, data, m_blockSize); - m_buffer[number].m_used = true; + ::memcpy(m_buffer[index].m_data, data, m_blockSize); + m_buffer[index].m_used = true; if (!m_timer.isRunning()) m_timer.start(); @@ -98,8 +104,11 @@ JB_STATUS CJitterBuffer::getData(unsigned char* data) if (m_headSequenceNumber > sequenceNumber) return JBS_NO_DATA; - if (m_buffer[m_headSequenceNumber].m_used) { - ::memcpy(data, m_buffer[m_headSequenceNumber].m_data, m_blockSize); + 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++; From 1d33405a199b80cd760c0a42f60dda05b5397182 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 22 Nov 2017 14:14:25 +0000 Subject: [PATCH 03/11] Return the last valid data if none exists when called. --- JitterBuffer.cpp | 21 +++++++++++++++++++-- JitterBuffer.h | 3 +++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index eed5822..ac8a8c2 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -29,7 +29,9 @@ m_blockCount(0U), m_timer(1000U, 0U, jitterTime), m_stopWatch(), m_buffer(NULL), -m_headSequenceNumber(0U) +m_headSequenceNumber(0U), +m_lastData(NULL), +m_lastDataValid(false) { assert(blockSize > 0U); assert(blockTime > 0U); @@ -43,6 +45,8 @@ m_headSequenceNumber(0U) 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(); } @@ -52,6 +56,7 @@ CJitterBuffer::~CJitterBuffer() delete[] m_buffer[i].m_data; delete[] m_buffer; + delete[] m_lastData; } bool CJitterBuffer::addData(const unsigned char* data, unsigned int sequenceNumber) @@ -110,11 +115,21 @@ JB_STATUS CJitterBuffer::getData(unsigned char* data) ::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_blockSize); + m_lastDataValid = true; + m_headSequenceNumber++; 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); + m_headSequenceNumber++; return JBS_REPEAT; @@ -126,6 +141,8 @@ void CJitterBuffer::reset() m_buffer[i].m_used = false; m_headSequenceNumber = 0U; + + m_lastDataValid = false; m_timer.stop(); } diff --git a/JitterBuffer.h b/JitterBuffer.h index 951e8c0..6d985ca 100644 --- a/JitterBuffer.h +++ b/JitterBuffer.h @@ -57,6 +57,9 @@ private: JitterEntry* m_buffer; unsigned int m_headSequenceNumber; + + unsigned char* m_lastData; + bool m_lastDataValid; }; #endif From ce891019d34500ce79af64d5c8ea523929002278 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 11:54:45 +0000 Subject: [PATCH 04/11] Basic jitter buffer for DMR, unfinished work. --- DMRData.cpp | 15 ++++- DMRData.h | 8 ++- DMRNetwork.cpp | 145 +++++++++++++++++++++++++++++------------------ DMRNetwork.h | 30 +++++----- JitterBuffer.cpp | 4 +- JitterBuffer.h | 2 +- MMDVMHost.cpp | 2 +- 7 files changed, 130 insertions(+), 76 deletions(-) diff --git a/DMRData.cpp b/DMRData.cpp index b9308a2..0b50e07 100644 --- a/DMRData.cpp +++ b/DMRData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 Jonathan Naylor, G4KLX + * Copyright (C) 2015,2016,2017 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 @@ -29,6 +29,7 @@ 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) @@ -45,6 +46,7 @@ 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) @@ -68,6 +70,7 @@ 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; @@ -138,6 +141,16 @@ 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 5a5be24..b06f416 100644 --- a/DMRData.h +++ b/DMRData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015,2016 by Jonathan Naylor, G4KLX + * Copyright (C) 2015,2016,2017 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 @@ -45,11 +45,14 @@ 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); unsigned char getRSSI() const; - void setRSSI(unsigned char ber); + void setRSSI(unsigned char rssi); void setData(const unsigned char* buffer); unsigned int getData(unsigned char* buffer) const; @@ -62,6 +65,7 @@ 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 dce6379..e840cdd 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -31,7 +31,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) : +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, unsigned int jitter) : m_address(), m_port(port), m_id(NULL), @@ -43,6 +43,7 @@ m_socket(local), m_enabled(false), m_slot1(slot1), m_slot2(slot2), +m_jitterBuffers(NULL), m_hwType(hwType), m_status(WAITING_CONNECT), m_retryTimer(1000U, 10U), @@ -69,17 +70,22 @@ 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_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_streamId[0U] = 0x00U; m_streamId[1U] = 0x00U; + m_jitterBuffers[1U] = new CJitterBuffer(60U, DMR_SLOT_TIME, jitter, 256U); + m_jitterBuffers[2U] = new CJitterBuffer(60U, DMR_SLOT_TIME, jitter, 256U); + m_id[0U] = id >> 24; m_id[1U] = id >> 16; m_id[2U] = id >> 8; @@ -91,10 +97,14 @@ m_beacon(false) CDMRNetwork::~CDMRNetwork() { - delete[] m_buffer; + delete m_jitterBuffers[1U]; + delete m_jitterBuffers[2U]; + + delete[] m_buffer; delete[] m_salt; delete[] m_streamId; delete[] m_id; + delete[] m_jitterBuffers; } void CDMRNetwork::setOptions(const std::string& options) @@ -138,64 +148,77 @@ bool CDMRNetwork::read(CDMRData& data) if (m_status != RUNNING) return false; - if (m_rxData.isEmpty()) - return false; + if (!m_rxData.isEmpty()) { + unsigned char length = 0U; - unsigned char length = 0U; + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); - m_rxData.getData(&length, 1U); - m_rxData.getData(m_buffer, length); + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - // Is this a data packet? - if (::memcmp(m_buffer, "DMRD", 4U) != 0) - return false; + bool wanted = true; - unsigned char seqNo = m_buffer[4U]; + // DMO mode slot disabling + if (slotNo == 1U && !m_duplex) + wanted = false; - unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + wanted = false; + if (slotNo == 2U && !m_slot2) + wanted = false; - unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); - - unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - - // DMO mode slot disabling - if (slotNo == 1U && !m_duplex) - return false; - - // Individual slot disabling - if (slotNo == 1U && !m_slot1) - return false; - if (slotNo == 2U && !m_slot2) - return false; - - 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); + if (wanted) { + unsigned char seqNo = m_buffer[4U]; + m_jitterBuffers[slotNo]->addData(m_buffer, seqNo); + } + } } - return true; + for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { + JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer); + if (status != JBS_NO_DATA) { + unsigned char seqNo = m_buffer[4U]; + + unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0); + + unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0); + + 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); + data.setMissing(status == JBS_MISSING); + + 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 true; + } + } + + return false; } bool CDMRNetwork::write(const CDMRData& data) @@ -339,6 +362,9 @@ void CDMRNetwork::close() void CDMRNetwork::clock(unsigned int ms) { + m_jitterBuffers[1U]->clock(ms); + m_jitterBuffers[2U]->clock(ms); + if (m_status == WAITING_CONNECT) { m_retryTimer.clock(ms); if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { @@ -480,6 +506,13 @@ void CDMRNetwork::clock(unsigned int ms) } } +void CDMRNetwork::reset(unsigned int slotNo) +{ + assert(slotNo == 1U || slotNo == 2U); + + m_jitterBuffers[slotNo]->reset(); +} + bool CDMRNetwork::writeLogin() { unsigned char buffer[8U]; diff --git a/DMRNetwork.h b/DMRNetwork.h index cc9cae4..d475d90 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -19,6 +19,7 @@ #if !defined(DMRNetwork_H) #define DMRNetwork_H +#include "JitterBuffer.h" #include "UDPSocket.h" #include "Timer.h" #include "RingBuffer.h" @@ -31,7 +32,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); + 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, unsigned int jitter); ~CDMRNetwork(); void setOptions(const std::string& options); @@ -54,21 +55,24 @@ public: void clock(unsigned int ms); + void reset(unsigned int slotNo); + void close(); private: - in_addr m_address; - unsigned int m_port; - uint8_t* m_id; - std::string m_password; - bool m_duplex; - const char* m_version; - bool m_debug; - CUDPSocket m_socket; - bool m_enabled; - bool m_slot1; - bool m_slot2; - HW_TYPE m_hwType; + in_addr m_address; + unsigned int m_port; + uint8_t* m_id; + std::string m_password; + bool m_duplex; + const char* m_version; + bool m_debug; + CUDPSocket m_socket; + bool m_enabled; + bool m_slot1; + bool m_slot2; + CJitterBuffer** m_jitterBuffers; + HW_TYPE m_hwType; enum STATUS { WAITING_CONNECT, diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index ac8a8c2..3a12efd 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -131,8 +131,8 @@ JB_STATUS CJitterBuffer::getData(unsigned char* data) ::memset(data, 0x00U, m_blockSize); m_headSequenceNumber++; - - return JBS_REPEAT; + + return JBS_MISSING; } void CJitterBuffer::reset() diff --git a/JitterBuffer.h b/JitterBuffer.h index 6d985ca..74fb1d8 100644 --- a/JitterBuffer.h +++ b/JitterBuffer.h @@ -25,7 +25,7 @@ enum JB_STATUS { JBS_NO_DATA, JBS_DATA, - JBS_REPEAT + JBS_MISSING }; class CJitterBuffer { diff --git a/MMDVMHost.cpp b/MMDVMHost.cpp index 89d2a3e..1178cbb 100644 --- a/MMDVMHost.cpp +++ b/MMDVMHost.cpp @@ -946,7 +946,7 @@ bool CMMDVMHost::createDMRNetwork() 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); + m_dmrNetwork = new CDMRNetwork(address, port, local, id, password, m_duplex, VERSION, debug, slot1, slot2, hwType, jitter); std::string options = m_conf.getDMRNetworkOptions(); if (!options.empty()) { From e1800c0fe03f470475f1daba1a284cf898868e94 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 13:18:37 +0000 Subject: [PATCH 05/11] 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); } From 17f38bcab324b81f5c528c3272410ea1f0dcd38d Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 13:34:29 +0000 Subject: [PATCH 06/11] Add debugging messages to teh jitter buffer class. --- JitterBuffer.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 85716c2..6ef0386 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -18,6 +18,8 @@ #include "JitterBuffer.h" +#include "Log.h" + #include #include @@ -70,11 +72,15 @@ bool CJitterBuffer::addData(const unsigned char* data, unsigned int length, unsi // Is the data out of sequence? if (headSequenceNumber < tailSequenceNumber) { - if (sequenceNumber < headSequenceNumber || sequenceNumber >= tailSequenceNumber) + if (sequenceNumber < headSequenceNumber || sequenceNumber >= tailSequenceNumber) { + LogInfo("JitterBuffer: rejecting frame with seqNo=%u, head=%u, tail=%u", sequenceNumber, headSequenceNumber, tailSequenceNumber); return false; + } } else { - if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) + if (sequenceNumber >= tailSequenceNumber && sequenceNumber < headSequenceNumber) { + LogInfo("JitterBuffer: rejecting frame with seqNo=%u, head=%u, tail=%u", sequenceNumber, headSequenceNumber, tailSequenceNumber); return false; + } } unsigned int number; @@ -86,8 +92,10 @@ 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_length > 0U) { + LogInfo("JitterBuffer: rejecting frame with seqNo=%u, already exists", sequenceNumber); return false; + } ::memcpy(m_buffer[index].m_data, data, length); m_buffer[index].m_length = length; From a9f6220162ec0f9c5f494e486fd593d97c4bbab2 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 16:19:09 +0000 Subject: [PATCH 07/11] Allow for a clean compiel on Linux. --- JitterBuffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 6ef0386..8f74b50 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -22,6 +22,7 @@ #include #include +#include CJitterBuffer::CJitterBuffer(unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, unsigned int topSequenceNumber) : m_blockSize(blockSize), From 93e3c84d8b5b40b6b8fe92a7c4365431ec51a3ab Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 16:56:10 +0000 Subject: [PATCH 08/11] Increase the jitter buffer size. --- JitterBuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JitterBuffer.cpp b/JitterBuffer.cpp index 8f74b50..087285d 100644 --- a/JitterBuffer.cpp +++ b/JitterBuffer.cpp @@ -41,7 +41,7 @@ m_lastDataLength(0U) assert(jitterTime > 0U); assert(topSequenceNumber > 0U); - m_blockCount = jitterTime / blockTime + 1U; + m_blockCount = (jitterTime / blockTime) * 2U + 1U; m_buffer = new JitterEntry[m_blockCount]; From d87877e460621395afbdbf298ff0e433587fab8e Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 24 Nov 2017 08:53:39 +0000 Subject: [PATCH 09/11] Re-add the small delay in the start of transmission of DMR network data. --- DMRSlot.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/DMRSlot.cpp b/DMRSlot.cpp index 9925721..c6ab1f5 100644 --- a/DMRSlot.cpp +++ b/DMRSlot.cpp @@ -1043,6 +1043,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + // Put a small delay into starting transmission + writeQueueNet(m_idle); + writeQueueNet(m_idle); + writeQueueNet(m_idle); + if (m_duplex) { for (unsigned int i = 0U; i < NO_HEADERS_DUPLEX; i++) writeQueueNet(data); @@ -1082,6 +1087,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + // Put a small delay into starting transmission + writeQueueNet(m_idle); + writeQueueNet(m_idle); + writeQueueNet(m_idle); + // Create a dummy start frame unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; @@ -1223,7 +1233,8 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) // Put a small delay into starting transmission writeQueueNet(m_idle); writeQueueNet(m_idle); - + writeQueueNet(m_idle); + writeQueueNet(data); m_netState = RS_NET_DATA; @@ -1263,6 +1274,11 @@ void CDMRSlot::writeNetwork(const CDMRData& dmrData) m_modem->writeDMRAbort(m_slotNo); } + // Put a small delay into starting transmission + writeQueueNet(m_idle); + writeQueueNet(m_idle); + writeQueueNet(m_idle); + // Create a dummy start frame unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U]; From baef6c962ed962c1d10b29e576fb7d75a422f47f Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 24 Nov 2017 09:02:32 +0000 Subject: [PATCH 10/11] Simplify the logic by removing the ring buffer. --- DMRNetwork.cpp | 54 +++++++++++++++++++------------------------------- DMRNetwork.h | 5 ++--- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index 4ff02f4..f478a89 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -51,7 +51,6 @@ 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), @@ -148,35 +147,6 @@ bool CDMRNetwork::read(CDMRData& data) if (m_status != RUNNING) return false; - if (!m_rxData.isEmpty()) { - unsigned char length = 0U; - - m_rxData.getData(&length, 1U); - m_rxData.getData(m_buffer, length); - - // Is this a data packet? - if (::memcmp(m_buffer, "DMRD", 4U) == 0) { - unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; - - bool wanted = true; - - // DMO mode slot disabling - if (slotNo == 1U && !m_duplex) - wanted = false; - - // Individual slot disabling - if (slotNo == 1U && !m_slot1) - wanted = false; - if (slotNo == 2U && !m_slot2) - wanted = false; - - if (wanted) { - unsigned char seqNo = m_buffer[4U]; - m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); - } - } - } - for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { unsigned int length = 0U; JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer, length); @@ -403,10 +373,7 @@ void CDMRNetwork::clock(unsigned int ms) if (m_enabled) { if (m_debug) CUtils::dump(1U, "Network Received", m_buffer, length); - - unsigned char len = length; - m_rxData.addData(&len, 1U); - m_rxData.addData(m_buffer, len); + receiveData(m_buffer, length); } } else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) { if (m_status == RUNNING) { @@ -514,6 +481,25 @@ void CDMRNetwork::reset(unsigned int slotNo) m_jitterBuffers[slotNo]->reset(); } +void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length) +{ + unsigned int slotNo = (m_buffer[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; + + unsigned char seqNo = m_buffer[4U]; + + m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); +} + bool CDMRNetwork::writeLogin() { unsigned char buffer[8U]; diff --git a/DMRNetwork.h b/DMRNetwork.h index d475d90..f54e440 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -22,7 +22,6 @@ #include "JitterBuffer.h" #include "UDPSocket.h" #include "Timer.h" -#include "RingBuffer.h" #include "DMRData.h" #include "Defines.h" @@ -90,8 +89,6 @@ private: unsigned char* m_salt; uint32_t* m_streamId; - CRingBuffer m_rxData; - std::string m_options; std::string m_callsign; @@ -115,6 +112,8 @@ private: bool writePing(); bool write(const unsigned char* data, unsigned int length); + + void receiveData(const unsigned char* data, unsigned int length); }; #endif From d4d26fc05f92d20c7fad5e3e80ad8bd31ba71dd4 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Fri, 24 Nov 2017 16:20:01 +0000 Subject: [PATCH 11/11] Revert "Simplify the logic by removing the ring buffer." This reverts commit baef6c962ed962c1d10b29e576fb7d75a422f47f. --- DMRNetwork.cpp | 54 +++++++++++++++++++++++++++++++------------------- DMRNetwork.h | 5 +++-- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/DMRNetwork.cpp b/DMRNetwork.cpp index f478a89..4ff02f4 100644 --- a/DMRNetwork.cpp +++ b/DMRNetwork.cpp @@ -51,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), @@ -147,6 +148,35 @@ bool CDMRNetwork::read(CDMRData& data) if (m_status != RUNNING) return false; + if (!m_rxData.isEmpty()) { + unsigned char length = 0U; + + m_rxData.getData(&length, 1U); + m_rxData.getData(m_buffer, length); + + // Is this a data packet? + if (::memcmp(m_buffer, "DMRD", 4U) == 0) { + unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U; + + bool wanted = true; + + // DMO mode slot disabling + if (slotNo == 1U && !m_duplex) + wanted = false; + + // Individual slot disabling + if (slotNo == 1U && !m_slot1) + wanted = false; + if (slotNo == 2U && !m_slot2) + wanted = false; + + if (wanted) { + unsigned char seqNo = m_buffer[4U]; + m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); + } + } + } + for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) { unsigned int length = 0U; JB_STATUS status = m_jitterBuffers[slotNo]->getData(m_buffer, length); @@ -373,7 +403,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) { @@ -481,25 +514,6 @@ void CDMRNetwork::reset(unsigned int slotNo) m_jitterBuffers[slotNo]->reset(); } -void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length) -{ - unsigned int slotNo = (m_buffer[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; - - unsigned char seqNo = m_buffer[4U]; - - m_jitterBuffers[slotNo]->addData(m_buffer, length, seqNo); -} - bool CDMRNetwork::writeLogin() { unsigned char buffer[8U]; diff --git a/DMRNetwork.h b/DMRNetwork.h index f54e440..d475d90 100644 --- a/DMRNetwork.h +++ b/DMRNetwork.h @@ -22,6 +22,7 @@ #include "JitterBuffer.h" #include "UDPSocket.h" #include "Timer.h" +#include "RingBuffer.h" #include "DMRData.h" #include "Defines.h" @@ -89,6 +90,8 @@ private: unsigned char* m_salt; uint32_t* m_streamId; + CRingBuffer m_rxData; + std::string m_options; std::string m_callsign; @@ -112,8 +115,6 @@ private: bool writePing(); bool write(const unsigned char* data, unsigned int length); - - void receiveData(const unsigned char* data, unsigned int length); }; #endif