From fc08cf95f360b3a6000e503a7f66e93ff02f6164 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Wed, 27 May 2020 13:49:55 +0100 Subject: [PATCH] Update to the latest Kenwood protocol handler. --- NXDNReflector/KenwoodNetwork.cpp | 472 ++++++++++++++++++++++++------- NXDNReflector/KenwoodNetwork.h | 31 +- NXDNReflector/UDPSocket.cpp | 30 +- NXDNReflector/UDPSocket.h | 6 +- NXDNReflector/Version.h | 2 +- 5 files changed, 432 insertions(+), 109 deletions(-) diff --git a/NXDNReflector/KenwoodNetwork.cpp b/NXDNReflector/KenwoodNetwork.cpp index 979c021..8a872c0 100644 --- a/NXDNReflector/KenwoodNetwork.cpp +++ b/NXDNReflector/KenwoodNetwork.cpp @@ -24,6 +24,7 @@ #include #include #include +#include const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; @@ -36,25 +37,37 @@ const unsigned int RTP_PORT = 64000U; const unsigned int RTCP_PORT = 64001U; CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) : -m_rtcpSocket(RTCP_PORT), m_rtpSocket(RTP_PORT), -m_stopWatch(), +m_rtcpSocket(RTCP_PORT), m_address(), +m_headerSeen(false), +m_seen1(false), +m_seen2(false), +m_seen3(false), +m_seen4(false), +m_sacch(NULL), +m_sessionId(1U), m_seqNo(0U), -m_timeStamp(0U), m_ssrc(0U), m_debug(debug), -m_timer(1000U, 0U, 200U) +m_startSecs(0U), +m_startUSecs(0U), +m_rtcpTimer(1000U, 0U, 200U), +m_hangTimer(1000U, 5U), +m_hangType(0U), +m_hangSrc(0U), +m_hangDst(0U) { assert(!address.empty()); - m_address = CUDPSocket::lookup(address); + m_sacch = new unsigned char[10U]; - ::srand((unsigned int)m_stopWatch.time()); + m_address = CUDPSocket::lookup(address); } CKenwoodNetwork::~CKenwoodNetwork() { + delete[] m_sacch; } bool CKenwoodNetwork::open() @@ -72,7 +85,7 @@ bool CKenwoodNetwork::open() return false; } - m_ssrc = ::rand(); + m_ssrc = m_rtpSocket.getLocalAddress(); return true; } @@ -107,12 +120,12 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) outData[3U] = inData[3U]; // FACCH 1+2 - outData[4U] = outData[14U] = inData[6U]; - outData[5U] = outData[15U] = inData[5U]; - outData[6U] = outData[16U] = inData[8U]; - outData[7U] = outData[17U] = inData[7U]; - outData[8U] = outData[18U] = inData[10U]; - outData[9U] = outData[19U] = inData[9U]; + outData[4U] = outData[14U] = inData[6U]; + outData[5U] = outData[15U] = inData[5U]; + outData[6U] = outData[16U] = inData[8U]; + outData[7U] = outData[17U] = inData[7U]; + outData[8U] = outData[18U] = inData[10U]; + outData[9U] = outData[19U] = inData[9U]; outData[10U] = outData[20U] = inData[12U]; outData[11U] = outData[21U] = inData[11U]; @@ -122,13 +135,16 @@ bool CKenwoodNetwork::processIcomVoiceHeader(const unsigned char* inData) switch (inData[5U] & 0x3FU) { case 0x01U: - m_timer.start(); - writeRTCPData(type, src, dst); + m_hangTimer.stop(); + m_rtcpTimer.start(); + writeRTCPStart(); return writeRTPVoiceHeader(outData); - case 0x08U: - m_timer.stop(); - writeRTCPData(type, src, dst); - return writeRTPVoiceTrailer(outData); + case 0x08U: { + m_hangTimer.start(); + bool ret = writeRTPVoiceTrailer(outData); + writeRTCPHang(type, src, dst); + return ret; + } default: return false; } @@ -224,23 +240,27 @@ bool CKenwoodNetwork::writeRTPVoiceHeader(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; - m_timeStamp = (unsigned long)m_stopWatch.time(); - - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + m_sessionId++; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -267,19 +287,26 @@ bool CKenwoodNetwork::writeRTPVoiceTrailer(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; buffer[10U] = (m_ssrc >> 8) & 0xFFU; buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x03U; buffer[18U] = 0x04U; @@ -306,21 +333,26 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) buffer[0U] = 0x80U; buffer[1U] = 0x66U; + m_seqNo++; buffer[2U] = (m_seqNo >> 8) & 0xFFU; buffer[3U] = (m_seqNo >> 0) & 0xFFU; - m_seqNo++; - buffer[4U] = (m_timeStamp >> 24) & 0xFFU; - buffer[5U] = (m_timeStamp >> 16) & 0xFFU; - buffer[6U] = (m_timeStamp >> 8) & 0xFFU; - buffer[7U] = (m_timeStamp >> 0) & 0xFFU; - m_timeStamp += 640U; + unsigned long timeStamp = getTimeStamp(); + buffer[4U] = (timeStamp >> 24) & 0xFFU; + buffer[5U] = (timeStamp >> 16) & 0xFFU; + buffer[6U] = (timeStamp >> 8) & 0xFFU; + buffer[7U] = (timeStamp >> 0) & 0xFFU; buffer[8U] = (m_ssrc >> 24) & 0xFFU; buffer[9U] = (m_ssrc >> 16) & 0xFFU; - buffer[10U] = (m_ssrc >> 8) & 0xFFU; - buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[10U] = (m_ssrc >> 8) & 0xFFU; + buffer[11U] = (m_ssrc >> 0) & 0xFFU; + buffer[12U] = m_sessionId; + + buffer[13U] = 0x00U; + buffer[14U] = 0x00U; + buffer[15U] = 0x00U; buffer[16U] = 0x03U; buffer[17U] = 0x02U; buffer[18U] = 0x04U; @@ -337,30 +369,59 @@ bool CKenwoodNetwork::writeRTPVoiceData(const unsigned char* data) return m_rtpSocket.write(buffer, 59U, m_address, RTP_PORT); } -bool CKenwoodNetwork::writeRTCPPing() +bool CKenwoodNetwork::writeRTCPStart() { +#if defined(_WIN32) || defined(_WIN64) + time_t now; + ::time(&now); + + m_startSecs = uint32_t(now); + + SYSTEMTIME st; + ::GetSystemTime(&st); + + m_startUSecs = st.wMilliseconds * 1000U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + m_startSecs = tod.tv_sec; + m_startUSecs = tod.tv_usec; +#endif + unsigned char buffer[30U]; ::memset(buffer, 0x00U, 30U); buffer[0U] = 0x8AU; buffer[1U] = 0xCCU; - + buffer[2U] = 0x00U; buffer[3U] = 0x06U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; buffer[10U] = 'N'; buffer[11U] = 'E'; + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; + + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; + buffer[22U] = 0x02U; buffer[24U] = 0x01U; - buffer[25U] = 0x01U; + + buffer[27U] = 0x0AU; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); @@ -368,33 +429,84 @@ bool CKenwoodNetwork::writeRTCPPing() return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT); } -bool CKenwoodNetwork::writeRTCPData(unsigned char type, unsigned short src, unsigned short dst) +bool CKenwoodNetwork::writeRTCPPing() { - unsigned char buffer[20U]; - ::memset(buffer, 0x00U, 20U); + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); - buffer[0U] = 0x8BU; + buffer[0U] = 0x8AU; buffer[1U] = 0xCCU; - - buffer[3U] = 0x04U; + buffer[2U] = 0x00U; + buffer[3U] = 0x06U; buffer[4U] = (m_ssrc >> 24) & 0xFFU; buffer[5U] = (m_ssrc >> 16) & 0xFFU; - buffer[6U] = (m_ssrc >> 8) & 0xFFU; - buffer[7U] = (m_ssrc >> 0) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; buffer[8U] = 'K'; buffer[9U] = 'W'; buffer[10U] = 'N'; buffer[11U] = 'E'; - buffer[12U] = (src >> 8) & 0xFFU; - buffer[13U] = (src >> 0) & 0xFFU; + buffer[12U] = (m_startSecs >> 24) & 0xFFU; + buffer[13U] = (m_startSecs >> 16) & 0xFFU; + buffer[14U] = (m_startSecs >> 8) & 0xFFU; + buffer[15U] = (m_startSecs >> 0) & 0xFFU; - buffer[14U] = (dst >> 8) & 0xFFU; - buffer[15U] = (dst >> 0) & 0xFFU; + buffer[16U] = (m_startUSecs >> 24) & 0xFFU; + buffer[17U] = (m_startUSecs >> 16) & 0xFFU; + buffer[18U] = (m_startUSecs >> 8) & 0xFFU; + buffer[19U] = (m_startUSecs >> 0) & 0xFFU; - buffer[16U] = type; + buffer[22U] = 0x02U; + + buffer[24U] = 0x01U; + + buffer[27U] = 0x7BU; + + if (m_debug) + CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 28U); + + return m_rtcpSocket.write(buffer, 28U, m_address, RTCP_PORT); +} + +bool CKenwoodNetwork::writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst) +{ + m_hangType = type; + m_hangSrc = src; + m_hangDst = dst; + + return writeRTCPHang(); +} + +bool CKenwoodNetwork::writeRTCPHang() +{ + unsigned char buffer[30U]; + ::memset(buffer, 0x00U, 30U); + + buffer[0U] = 0x8BU; + buffer[1U] = 0xCCU; + buffer[2U] = 0x00U; + buffer[3U] = 0x04U; + + buffer[4U] = (m_ssrc >> 24) & 0xFFU; + buffer[5U] = (m_ssrc >> 16) & 0xFFU; + buffer[6U] = (m_ssrc >> 8) & 0xFFU; + buffer[7U] = (m_ssrc >> 0) & 0xFFU; + + buffer[8U] = 'K'; + buffer[9U] = 'W'; + buffer[10U] = 'N'; + buffer[11U] = 'E'; + + buffer[12U] = (m_hangSrc >> 8) & 0xFFU; + buffer[13U] = (m_hangSrc >> 0) & 0xFFU; + + buffer[14U] = (m_hangDst >> 8) & 0xFFU; + buffer[15U] = (m_hangDst >> 0) & 0xFFU; + + buffer[16U] = m_hangType; if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Sent", buffer, 20U); @@ -409,26 +521,23 @@ unsigned int CKenwoodNetwork::read(unsigned char* data) unsigned char dummy[BUFFER_LENGTH]; readRTCP(dummy); - bool ret; - unsigned int len = readRTP(data); - if (len > 0U) { - switch (data[9U]) { - case 0x05U: // Voice header or trailer - ret = processKenwoodVoiceHeader(data); - if (!ret) - return 0U; - return 33U; - case 0x08U: // Voice data - processKenwoodVoiceData(data); - return 33U; - default: - break; - } + switch (len) { + case 0U: // Nothing received + return 0U; + case 35U: // Voice header or trailer + return processKenwoodVoiceHeader(data); + case 47U: // Voice data + if (m_headerSeen) + return processKenwoodVoiceData(data); + else + return processKenwoodVoiceLateEntry(data); + case 31U: // Data + return processKenwoodData(data); + default: + CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); + return 0U; } - - CUtils::dump(5U, "Unknown data received from the Kenwood network", data, len); - return 0U; } unsigned int CKenwoodNetwork::readRTP(unsigned char* data) @@ -444,19 +553,14 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != RTP_PORT) { - LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTP_PORT, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTP Data Received", buffer, length); - if (length != 47 && length != 59) { - LogError("Invalid RTP length of %d", length); - return 0U; - } - ::memcpy(data, buffer + 12U, length - 12U); return length - 12U; @@ -475,19 +579,14 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return 0U; // Check if the data is for us - if (m_address.s_addr != address.s_addr || port != RTCP_PORT) { - LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, RTCP_PORT, port); + if (m_address.s_addr != address.s_addr) { + LogMessage("Kenwood RTCP packet received from an invalid source, %08X != %08X", m_address.s_addr, address.s_addr); return 0U; } if (m_debug) CUtils::dump(1U, "Kenwood Network RTCP Data Received", buffer, length); - if (length != 20 && length != 28) { - LogError("Invalid RTCP length of %d", length); - return 0U; - } - if (::memcmp(buffer + 8U, "KWNE", 4U) != 0) { LogError("Missing RTCP KWNE signature"); return 0U; @@ -508,14 +607,23 @@ void CKenwoodNetwork::close() void CKenwoodNetwork::clock(unsigned int ms) { - m_timer.clock(ms); - if (m_timer.isRunning() && m_timer.hasExpired()) { - writeRTCPPing(); - m_timer.start(); + m_rtcpTimer.clock(ms); + if (m_rtcpTimer.isRunning() && m_rtcpTimer.hasExpired()) { + if (m_hangTimer.isRunning()) + writeRTCPHang(); + else + writeRTCPPing(); + m_rtcpTimer.start(); + } + + m_hangTimer.clock(ms); + if (m_hangTimer.isRunning() && m_hangTimer.hasExpired()) { + m_rtcpTimer.stop(); + m_hangTimer.stop(); } } -bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) { assert(inData != NULL); @@ -552,15 +660,27 @@ bool CKenwoodNetwork::processKenwoodVoiceHeader(unsigned char* inData) switch (outData[5U] & 0x3FU) { case 0x01U: + ::memcpy(inData, outData, 33U); + m_headerSeen = true; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; case 0x08U: ::memcpy(inData, outData, 33U); - return true; + m_headerSeen = false; + m_seen1 = false; + m_seen2 = false; + m_seen3 = false; + m_seen4 = false; + return 33U; default: - return false; + return 0U; } } -void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) +unsigned int CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) { assert(inData != NULL); @@ -642,4 +762,162 @@ void CKenwoodNetwork::processKenwoodVoiceData(unsigned char* inData) } ::memcpy(inData, outData, 33U); + + return 33U; +} + +unsigned int CKenwoodNetwork::processKenwoodData(unsigned char* inData) +{ + if (inData[7U] != 0x09U && inData[7U] != 0x0BU && inData[7U] != 0x08U) + return 0U; + + unsigned char outData[50U]; + + if (inData[7U] == 0x09U || inData[7U] == 0x08U) { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + ::memcpy(inData, outData, 7U); + return 7U; + } else { + outData[0U] = 0x90U; + outData[1U] = inData[8U]; + outData[2U] = inData[7U]; + outData[3U] = inData[10U]; + outData[4U] = inData[9U]; + outData[5U] = inData[12U]; + outData[6U] = inData[11U]; + outData[7U] = inData[14U]; + outData[8U] = inData[13U]; + outData[9U] = inData[16U]; + outData[10U] = inData[15U]; + outData[11U] = inData[18U]; + outData[12U] = inData[17U]; + outData[13U] = inData[20U]; + outData[14U] = inData[19U]; + outData[15U] = inData[22U]; + outData[16U] = inData[21U]; + outData[17U] = inData[24U]; + outData[18U] = inData[23U]; + outData[19U] = inData[26U]; + outData[20U] = inData[25U]; + outData[21U] = inData[28U]; + outData[22U] = inData[27U]; + outData[23U] = inData[29U]; + ::memcpy(inData, outData, 24U); + return 24U; + } +} + +unsigned long CKenwoodNetwork::getTimeStamp() const +{ + unsigned long timeStamp = 0UL; + +#if defined(_WIN32) || defined(_WIN64) + SYSTEMTIME st; + ::GetSystemTime(&st); + + unsigned int hh = st.wHour; + unsigned int mm = st.wMinute; + unsigned int ss = st.wSecond; + unsigned int ms = st.wMilliseconds; + + timeStamp += hh * 3600U * 1000U * 80U; + timeStamp += mm * 60U * 1000U * 80U; + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#else + struct timeval tod; + ::gettimeofday(&tod, NULL); + + unsigned int ss = tod.tv_sec; + unsigned int ms = tod.tv_usec / 1000U; + + timeStamp += ss * 1000U * 80U; + timeStamp += ms * 80U; +#endif + + return timeStamp; +} + +unsigned int CKenwoodNetwork::processKenwoodVoiceLateEntry(unsigned char* inData) +{ + assert(inData != NULL); + + unsigned char sacch[4U]; + sacch[0U] = inData[12U]; + sacch[1U] = inData[11U]; + sacch[2U] = inData[14U]; + sacch[3U] = inData[13U]; + + switch (sacch[0U] & 0xC0U) { + case 0xC0U: + if (!m_seen1) { + unsigned int offset = 0U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen1 = true; + } + break; + case 0x80U: + if (!m_seen2) { + unsigned int offset = 18U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen2 = true; + } + break; + case 0x40U: + if (!m_seen3) { + unsigned int offset = 36U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen3 = true; + } + break; + case 0x00U: + if (!m_seen4) { + unsigned int offset = 54U; + for (unsigned int i = 8U; i < 26U; i++, offset++) { + bool b = READ_BIT(sacch, i) != 0U; + WRITE_BIT(m_sacch, offset, b); + } + m_seen4 = true; + } + break; + } + + if (!m_seen1 || !m_seen2 || !m_seen3 || !m_seen4) + return 0U; + + // Create a dummy header + // Header SACCH + inData[11U] = 0x10U; + inData[12U] = 0x01U; + inData[13U] = 0x00U; + inData[14U] = 0x00U; + + // Header FACCH + inData[15U] = m_sacch[1U]; + inData[16U] = m_sacch[0U]; + inData[17U] = m_sacch[3U]; + inData[18U] = m_sacch[2U]; + inData[19U] = m_sacch[5U]; + inData[20U] = m_sacch[4U]; + inData[21U] = m_sacch[7U]; + inData[22U] = m_sacch[6U]; + inData[23U] = 0x00U; + inData[24U] = m_sacch[8U]; + + return processKenwoodVoiceHeader(inData); } diff --git a/NXDNReflector/KenwoodNetwork.h b/NXDNReflector/KenwoodNetwork.h index 4c0ded9..0543efe 100644 --- a/NXDNReflector/KenwoodNetwork.h +++ b/NXDNReflector/KenwoodNetwork.h @@ -20,7 +20,6 @@ #define KenwoodNetwork_H #include "CoreNetwork.h" -#include "StopWatch.h" #include "UDPSocket.h" #include "Timer.h" @@ -45,25 +44,41 @@ public: private: CUDPSocket m_rtpSocket; CUDPSocket m_rtcpSocket; - CStopWatch m_stopWatch; in_addr m_address; - unsigned short m_seqNo; - unsigned long m_timeStamp; + bool m_headerSeen; + bool m_seen1; + bool m_seen2; + bool m_seen3; + bool m_seen4; + unsigned char* m_sacch; + uint8_t m_sessionId; + uint16_t m_seqNo; unsigned int m_ssrc; bool m_debug; - CTimer m_timer; + uint32_t m_startSecs; + uint32_t m_startUSecs; + CTimer m_rtcpTimer; + CTimer m_hangTimer; + unsigned char m_hangType; + unsigned short m_hangSrc; + unsigned short m_hangDst; bool processIcomVoiceHeader(const unsigned char* data); bool processIcomVoiceData(const unsigned char* data); - bool processKenwoodVoiceHeader(unsigned char* data); - void processKenwoodVoiceData(unsigned char* data); + unsigned int processKenwoodVoiceHeader(unsigned char* data); + unsigned int processKenwoodVoiceData(unsigned char* data); + unsigned int processKenwoodVoiceLateEntry(unsigned char* data); + unsigned int processKenwoodData(unsigned char* data); bool writeRTPVoiceHeader(const unsigned char* data); bool writeRTPVoiceData(const unsigned char* data); bool writeRTPVoiceTrailer(const unsigned char* data); + bool writeRTCPStart(); bool writeRTCPPing(); - bool writeRTCPData(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(unsigned char type, unsigned short src, unsigned short dst); + bool writeRTCPHang(); unsigned int readRTP(unsigned char* data); unsigned int readRTCP(unsigned char* data); + unsigned long getTimeStamp() const; }; #endif diff --git a/NXDNReflector/UDPSocket.cpp b/NXDNReflector/UDPSocket.cpp index 396f1f7..d651ab8 100644 --- a/NXDNReflector/UDPSocket.cpp +++ b/NXDNReflector/UDPSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2006-2016,2020 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 @@ -260,3 +260,31 @@ void CUDPSocket::close() ::close(m_fd); #endif } + +unsigned long CUDPSocket::getLocalAddress() const +{ + unsigned long address = 0UL; + + char hostname[80U]; + int ret = ::gethostname(hostname, 80); + if (ret == -1) + return 0UL; + + struct hostent* phe = ::gethostbyname(hostname); + if (phe == NULL) + return 0UL; + + if (phe->h_addrtype != AF_INET) + return 0UL; + + for (unsigned int i = 0U; phe->h_addr_list[i] != NULL; i++) { + struct in_addr addr; + ::memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); + if (addr.s_addr != INADDR_LOOPBACK) { + address = addr.s_addr; + break; + } + } + + return address; +} diff --git a/NXDNReflector/UDPSocket.h b/NXDNReflector/UDPSocket.h index e0af272..4c21a43 100644 --- a/NXDNReflector/UDPSocket.h +++ b/NXDNReflector/UDPSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX + * Copyright (C) 2009-2011,2013,2015,2016,2020 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 @@ -47,7 +47,9 @@ public: void close(); - static in_addr lookup(const std::string& hostName); + unsigned long getLocalAddress() const; + + static in_addr lookup(const std::string& hostName); private: std::string m_address; diff --git a/NXDNReflector/Version.h b/NXDNReflector/Version.h index 301ae35..0a67dd6 100644 --- a/NXDNReflector/Version.h +++ b/NXDNReflector/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200420"; +const char* VERSION = "20200427"; #endif