From ce891019d34500ce79af64d5c8ea523929002278 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Thu, 23 Nov 2017 11:54:45 +0000 Subject: [PATCH] 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()) {