From 842d2e0a5935d9011c43941f01cd270b3f1b66aa Mon Sep 17 00:00:00 2001 From: Tom Early Date: Fri, 10 May 2024 14:27:11 -0700 Subject: [PATCH 01/11] uses TCP instead of unix sockets --- .gitignore | 20 ++---------- Configure.cpp | 33 +++++++++++++++++--- Configure.h | 5 ++- Controller.cpp | 76 ++++++++++++++++++++++----------------------- Controller.h | 5 ++- IP.cpp | 1 + IP.h | 1 + Makefile | 4 +-- README.md | 2 +- TCSocket.cpp | 1 + TCSocket.h | 1 + UnixDgramSocket.cpp | 1 - UnixDgramSocket.h | 1 - config/tcd.ini | 7 +++-- 14 files changed, 86 insertions(+), 72 deletions(-) create mode 120000 IP.cpp create mode 120000 IP.h create mode 120000 TCSocket.cpp create mode 120000 TCSocket.h delete mode 120000 UnixDgramSocket.cpp delete mode 120000 UnixDgramSocket.h diff --git a/.gitignore b/.gitignore index d900137..ac9e54f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,24 +7,8 @@ *.o *.obj -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib +# Files +tcd.* # Visual Studio .vscode diff --git a/Configure.cpp b/Configure.cpp index 78d00d8..e585b02 100644 --- a/Configure.cpp +++ b/Configure.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "Configure.h" // ini file keywords @@ -30,7 +31,9 @@ #define DMRGAINOUT "DmrYsfGainOut" #define DSTARGAININ "DStarGainIn" #define DSTARGAINOUT "DStarGainOut" -#define TRANSCODED "Transcoded" +#define MODULES "Modules" +#define ADDRESS "Address" +#define PORT "Port" static inline void split(const std::string &s, char delim, std::vector &v) { @@ -63,7 +66,10 @@ static inline void trim(std::string &s) { bool CConfigure::ReadData(const std::string &path) // returns true on failure { - std::string modstmp; + std::regex IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended); + std::regex IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended); + + std::string modstmp, porttmp; std::ifstream cfgfile(path.c_str(), std::ifstream::in); if (! cfgfile.is_open()) { @@ -104,7 +110,11 @@ bool CConfigure::ReadData(const std::string &path) std::cout << "WARNING: missing key or value: '" << line << "'" << std::endl; continue; } - if (0 == key.compare(TRANSCODED)) + if (0 == key.compare(ADDRESS)) + address.assign(value); + else if (0 == key.compare(PORT)) + porttmp.assign(value); + else if (0 == key.compare(MODULES)) modstmp.assign(value); else if (0 == key.compare(DSTARGAININ)) dstar_in = getSigned(key, value); @@ -139,7 +149,22 @@ bool CConfigure::ReadData(const std::string &path) return true; } - std::cout << TRANSCODED << " = " << tcmods << std::endl; + if (! std::regex_match(address, IPv4RegEx) && ! std::regex_match(address, IPv6RegEx)) + { + std::cerr << "ERROR: '" << address << "' is malformed, Halt." << std::endl; + return true; + } + + port = std::strtoul(porttmp.c_str(), nullptr, 10); + if (port < 1025 || port > 49000) + { + std::cerr << "ERROR: Port '" << porttmp << "' must be between >1024 and <49000. Halt." << std::endl; + return true; + } + + std::cout << MODULES << " = " << tcmods << std::endl; + std::cout << ADDRESS << " = " << address << std::endl; + std::cout << PORT << " = " << port << std::endl; std::cout << DSTARGAININ << " = " << dstar_in << std::endl; std::cout << DSTARGAINOUT << " = " << dstar_out << std::endl; std::cout << DMRGAININ << " = " << dmr_in << std::endl; diff --git a/Configure.h b/Configure.h index e553f38..f5313df 100644 --- a/Configure.h +++ b/Configure.h @@ -32,10 +32,13 @@ public: bool ReadData(const std::string &path); int GetGain(EGainType gt) const; std::string GetTCMods(void) const { return tcmods; } + std::string GetAddress(void) const { return address; } + unsigned GetPort(void) const { return port; } private: // CFGDATA data; - std::string tcmods; + std::string tcmods, address; + uint16_t port; int dstar_in, dstar_out, dmr_in, dmr_out, usrp_tx, usrp_rx; int getSigned(const std::string &key, const std::string &value) const; diff --git a/Controller.cpp b/Controller.cpp index ad8cf95..1865ee9 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef USE_SW_AMBE2 #include #endif @@ -46,7 +47,7 @@ bool CController::Start() usrp_rx_num = calcNumerator(g_Conf.GetGain(EGainType::usrprx)); usrp_tx_num = calcNumerator(g_Conf.GetGain(EGainType::usrptx)); - if (InitVocoders() || reader.Open(REF2TC)) + if (InitVocoders() || tcClient.Initialize(g_Conf.GetAddress(), g_Conf.GetTCMods(), g_Conf.GetPort())) { keep_running = false; return true; @@ -70,7 +71,7 @@ void CController::Stop() if (c2Future.valid()) c2Future.get(); - reader.Close(); + tcClient.Close(); dstar_device->CloseDevice(); dmrsf_device->CloseDevice(); dstar_device.reset(); @@ -249,39 +250,42 @@ void CController::ReadReflectorThread() { while (keep_running) { - STCPacket tcpack; + std::queue> queue; // wait up to 100 ms to read something on the unix port - if (reader.Receive(&tcpack, 100)) + if (tcClient.Receive(queue, 100)) { - // create a shared pointer to a new packet - // there is only one CTranscoderPacket created for each new STCPacket received from the reflector - auto packet = std::make_shared(tcpack); - - switch (packet->GetCodecIn()) + while (! queue.empty()) { - case ECodecType::dstar: - dstar_device->AddPacket(packet); - break; - case ECodecType::dmr: -#ifdef USE_SW_AMBE2 - swambe2_queue.push(packet); -#else - dmrsf_device->AddPacket(packet); -#endif - break; - case ECodecType::p25: - imbe_queue.push(packet); - break; - case ECodecType::usrp: - usrp_queue.push(packet); - break; - case ECodecType::c2_1600: - case ECodecType::c2_3200: - codec2_queue.push(packet); - break; - default: - Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); - break; + // create a shared pointer to a new packet + // there is only one CTranscoderPacket created for each new STCPacket received from the reflector + auto packet = std::make_shared(*queue.front()); + queue.pop(); + switch (packet->GetCodecIn()) + { + case ECodecType::dstar: + dstar_device->AddPacket(packet); + break; + case ECodecType::dmr: + #ifdef USE_SW_AMBE2 + swambe2_queue.push(packet); + #else + dmrsf_device->AddPacket(packet); + #endif + break; + case ECodecType::p25: + imbe_queue.push(packet); + break; + case ECodecType::usrp: + usrp_queue.push(packet); + break; + case ECodecType::c2_1600: + case ECodecType::c2_3200: + codec2_queue.push(packet); + break; + default: + Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); + break; + } } } } @@ -595,14 +599,8 @@ void CController::ProcessUSRPThread() void CController::SendToReflector(std::shared_ptr packet) { - // open a socket to the reflector channel - CUnixDgramWriter socket; - std::string name(TC2REF); - name.append(1, packet->GetModule()); - socket.SetUp(name.c_str()); // send the packet over the socket - socket.Send(packet->GetTCPacket()); - // the socket will automatically close after sending + tcClient.Send(packet->GetTCPacket()); packet->Sent(); } diff --git a/Controller.h b/Controller.h index 0b65473..10555b8 100644 --- a/Controller.h +++ b/Controller.h @@ -29,7 +29,7 @@ #include "codec2.h" #include "DV3000.h" #include "DV3003.h" -#include "UnixDgramSocket.h" +#include "TCSocket.h" class CController { @@ -48,8 +48,7 @@ protected: std::future reflectorFuture, c2Future, imbeFuture, usrpFuture; std::unordered_map audio_store; std::unordered_map data_store; - CUnixDgramReader reader; - CUnixDgramWriter writer; + CTCClient tcClient; std::unordered_map> c2_16, c2_32; std::unique_ptr dstar_device, dmrsf_device; diff --git a/IP.cpp b/IP.cpp new file mode 120000 index 0000000..0d0f0e2 --- /dev/null +++ b/IP.cpp @@ -0,0 +1 @@ +../urfd/reflector/IP.cpp \ No newline at end of file diff --git a/IP.h b/IP.h new file mode 120000 index 0000000..d6ec9ce --- /dev/null +++ b/IP.h @@ -0,0 +1 @@ +../urfd/reflector/IP.h \ No newline at end of file diff --git a/Makefile b/Makefile index b67209f..541c745 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,9 @@ include tcd.mk GCC = g++ ifeq ($(debug), true) -CFLAGS = -ggdb3 -W -Werror -Icodec2 -MMD -MD -std=c++11 +CFLAGS = -ggdb3 -W -Werror -Icodec2 -MMD -MD -std=c++17 else -CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11 +CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++17 endif ifeq ($(swambe2), true) diff --git a/README.md b/README.md index d8a34ba..21ca73a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Currently, this program must be run locally with its paired URF reflector. Remot Only systemd-based operating systems are supported. Debian or Ubuntu is recommended. If you want to install this on a non-systemd based OS, you are on your own. Also, by default, *tcd* is built without gdb support. -The P25 IMBE software vocoder library is available [here](https://github.com/nostar/imbe_vocoder). See its README.md file for instructions for compiling and installating this library. +The P25 IMBE software vocoder library is available [here](https://github.com/nostar/imbe_vocoder). See its README.md file for instructions for compiling and installing this library. If you are running tcd on an ARM-base processor, you can opt to use a software-based vocoder library available [here](https://github.com/nostar/md380_vocoder) for DMR/YSF vocoding. This library is used for the AMBE+2 (DMR/YSF/NXDN) codec. If you are going to use this library, *tcd* must run on an ARM platform like a RPi. Using this software solution means that you only need one DVSI device to handle D-Star vocoding. diff --git a/TCSocket.cpp b/TCSocket.cpp new file mode 120000 index 0000000..7b6bde0 --- /dev/null +++ b/TCSocket.cpp @@ -0,0 +1 @@ +../urfd/reflector/TCSocket.cpp \ No newline at end of file diff --git a/TCSocket.h b/TCSocket.h new file mode 120000 index 0000000..55b7cbb --- /dev/null +++ b/TCSocket.h @@ -0,0 +1 @@ +../urfd/reflector/TCSocket.h \ No newline at end of file diff --git a/UnixDgramSocket.cpp b/UnixDgramSocket.cpp deleted file mode 120000 index ac38194..0000000 --- a/UnixDgramSocket.cpp +++ /dev/null @@ -1 +0,0 @@ -../urfd/reflector/UnixDgramSocket.cpp \ No newline at end of file diff --git a/UnixDgramSocket.h b/UnixDgramSocket.h deleted file mode 120000 index e0b3691..0000000 --- a/UnixDgramSocket.h +++ /dev/null @@ -1 +0,0 @@ -../urfd/reflector/UnixDgramSocket.h \ No newline at end of file diff --git a/config/tcd.ini b/config/tcd.ini index 15f68a4..cee1602 100644 --- a/config/tcd.ini +++ b/config/tcd.ini @@ -2,10 +2,13 @@ # # this is a comment -# VERY IMPORTANT: This need to be idential to the same line in the urfd ini file! +Port = 10100 +ServerAddress = 127.0.0.1 +# VERY IMPORTANT: This need to be idential to the same line in [Transcder] section of the urfd ini file! # This will either be a single module (for DVSI-3000), or # up to three modules (for DVSI-3003). -Transcoded = A +Modules = A + # All gain values are in dB. # Gain values are limited to -24 to +24. Typical values will usually be less. From 88046aba9e12b7872260b23026d250e3b9951a32 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 13 May 2024 05:20:00 -0700 Subject: [PATCH 02/11] formatting --- Controller.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 1865ee9..3779131 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -250,6 +250,8 @@ void CController::ReadReflectorThread() { while (keep_running) { + tcClient.CheckConnections(); + std::queue> queue; // wait up to 100 ms to read something on the unix port if (tcClient.Receive(queue, 100)) @@ -266,11 +268,11 @@ void CController::ReadReflectorThread() dstar_device->AddPacket(packet); break; case ECodecType::dmr: - #ifdef USE_SW_AMBE2 +#ifdef USE_SW_AMBE2 swambe2_queue.push(packet); - #else +#else dmrsf_device->AddPacket(packet); - #endif +#endif break; case ECodecType::p25: imbe_queue.push(packet); From 175ff2cde5a359838ba4885c60174caa9af2b66f Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 13 May 2024 13:40:50 -0700 Subject: [PATCH 03/11] Configure bug --- Configure.cpp | 6 +++--- config/tcd.ini | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Configure.cpp b/Configure.cpp index e585b02..c0c57ee 100644 --- a/Configure.cpp +++ b/Configure.cpp @@ -32,7 +32,7 @@ #define DSTARGAININ "DStarGainIn" #define DSTARGAINOUT "DStarGainOut" #define MODULES "Modules" -#define ADDRESS "Address" +#define SERVERADDRESS "ServerAddress" #define PORT "Port" static inline void split(const std::string &s, char delim, std::vector &v) @@ -110,7 +110,7 @@ bool CConfigure::ReadData(const std::string &path) std::cout << "WARNING: missing key or value: '" << line << "'" << std::endl; continue; } - if (0 == key.compare(ADDRESS)) + if (0 == key.compare(SERVERADDRESS)) address.assign(value); else if (0 == key.compare(PORT)) porttmp.assign(value); @@ -163,7 +163,7 @@ bool CConfigure::ReadData(const std::string &path) } std::cout << MODULES << " = " << tcmods << std::endl; - std::cout << ADDRESS << " = " << address << std::endl; + std::cout << SERVERADDRESS << " = " << address << std::endl; std::cout << PORT << " = " << port << std::endl; std::cout << DSTARGAININ << " = " << dstar_in << std::endl; std::cout << DSTARGAINOUT << " = " << dstar_out << std::endl; diff --git a/config/tcd.ini b/config/tcd.ini index cee1602..5758c86 100644 --- a/config/tcd.ini +++ b/config/tcd.ini @@ -5,8 +5,7 @@ Port = 10100 ServerAddress = 127.0.0.1 # VERY IMPORTANT: This need to be idential to the same line in [Transcder] section of the urfd ini file! -# This will either be a single module (for DVSI-3000), or -# up to three modules (for DVSI-3003). +# This will either be a single module (for DVSI-3000), or up to three modules (for DVSI-3003). Modules = A From 07509bd34740806c25dd677019eb6e35cb0f938a Mon Sep 17 00:00:00 2001 From: Tom Early Date: Tue, 14 May 2024 18:27:50 -0700 Subject: [PATCH 04/11] some redesign of TC socket --- Controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller.cpp b/Controller.cpp index 3779131..ce86d42 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -250,7 +250,7 @@ void CController::ReadReflectorThread() { while (keep_running) { - tcClient.CheckConnections(); + tcClient.ReConnect(); std::queue> queue; // wait up to 100 ms to read something on the unix port From 71aff903045f04a842d4596087f16b364e765ef0 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Thu, 16 May 2024 14:26:17 -0700 Subject: [PATCH 05/11] tweaking how the TC socket deals with errors --- Controller.cpp | 75 +++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index ce86d42..d598d7d 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -47,7 +47,7 @@ bool CController::Start() usrp_rx_num = calcNumerator(g_Conf.GetGain(EGainType::usrprx)); usrp_tx_num = calcNumerator(g_Conf.GetGain(EGainType::usrptx)); - if (InitVocoders() || tcClient.Initialize(g_Conf.GetAddress(), g_Conf.GetTCMods(), g_Conf.GetPort())) + if (InitVocoders() || tcClient.Open(g_Conf.GetAddress(), g_Conf.GetTCMods(), g_Conf.GetPort())) { keep_running = false; return true; @@ -250,44 +250,48 @@ void CController::ReadReflectorThread() { while (keep_running) { - tcClient.ReConnect(); - std::queue> queue; // wait up to 100 ms to read something on the unix port if (tcClient.Receive(queue, 100)) { - while (! queue.empty()) + if (tcClient.ReConnect()) + { + std::cerr << "Unrecoverable ERROR! Quitting..." << std::endl; + exit(1); + } + } + + while (! queue.empty()) + { + // create a shared pointer to a new packet + // there is only one CTranscoderPacket created for each new STCPacket received from the reflector + auto packet = std::make_shared(*queue.front()); + queue.pop(); + switch (packet->GetCodecIn()) { - // create a shared pointer to a new packet - // there is only one CTranscoderPacket created for each new STCPacket received from the reflector - auto packet = std::make_shared(*queue.front()); - queue.pop(); - switch (packet->GetCodecIn()) - { - case ECodecType::dstar: - dstar_device->AddPacket(packet); - break; - case ECodecType::dmr: + case ECodecType::dstar: + dstar_device->AddPacket(packet); + break; + case ECodecType::dmr: #ifdef USE_SW_AMBE2 - swambe2_queue.push(packet); + swambe2_queue.push(packet); #else - dmrsf_device->AddPacket(packet); + dmrsf_device->AddPacket(packet); #endif - break; - case ECodecType::p25: - imbe_queue.push(packet); - break; - case ECodecType::usrp: - usrp_queue.push(packet); - break; - case ECodecType::c2_1600: - case ECodecType::c2_3200: - codec2_queue.push(packet); - break; - default: - Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); - break; - } + break; + case ECodecType::p25: + imbe_queue.push(packet); + break; + case ECodecType::usrp: + usrp_queue.push(packet); + break; + case ECodecType::c2_1600: + case ECodecType::c2_3200: + codec2_queue.push(packet); + break; + default: + Dump(packet, "ERROR: Received a reflector packet with unknown Codec:"); + break; } } } @@ -602,7 +606,14 @@ void CController::ProcessUSRPThread() void CController::SendToReflector(std::shared_ptr packet) { // send the packet over the socket - tcClient.Send(packet->GetTCPacket()); + while (tcClient.Send(packet->GetTCPacket())) + { + if (tcClient.ReConnect()) + { + std::cerr << "Unrecoverable ERROR, quiting!" << std::endl; + exit(1); + } + } packet->Sent(); } From 0ca0629da65ee31461efe28a37237300b252e514 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Sat, 18 May 2024 10:08:27 -0700 Subject: [PATCH 06/11] added missing codecs to Dump --- Controller.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Controller.cpp b/Controller.cpp index d598d7d..07ebff1 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -676,6 +676,14 @@ void CController::Dump(const std::shared_ptr p, const std::st line << "**"; else if (ECodecType::c2_3200 == in) line << '*'; + if (p->P25IsSet()) + line << " P25"; + if (ECodecType::p25 == in) + line << "*"; + if (p->USRPIsSet()) + line << " USRP"; + if (ECodecType::usrp == in) + line << "*"; if (p->IsSecond()) line << " IsSecond"; if (p->IsLast()) From f85434420b7521fa505bb7736bc34b16e6428a41 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 20 May 2024 05:12:45 -0700 Subject: [PATCH 07/11] removed CTimer from STCPacket --- Controller.cpp | 2 +- TranscoderPacket.cpp | 5 ----- TranscoderPacket.h | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 07ebff1..82c78a7 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -659,7 +659,7 @@ void CController::RouteDmrPacket(std::shared_ptr packet) void CController::Dump(const std::shared_ptr p, const std::string &title) const { std::stringstream line; - line << title << " Mod='" << p->GetModule() << "' SID=" << std::showbase << std::hex << ntohs(p->GetStreamId()) << std::noshowbase << " ET:" << std::setprecision(3) << p->GetTimeMS(); + line << title << " Mod='" << p->GetModule() << "' SID=" << std::showbase << std::hex << ntohs(p->GetStreamId()) << std::noshowbase; ECodecType in = p->GetCodecIn(); if (p->DStarIsSet()) diff --git a/TranscoderPacket.cpp b/TranscoderPacket.cpp index 004333a..3611fb1 100644 --- a/TranscoderPacket.cpp +++ b/TranscoderPacket.cpp @@ -143,11 +143,6 @@ uint32_t CTranscoderPacket::GetSequence() const return tcpacket.sequence; } -double CTranscoderPacket::GetTimeMS() const -{ - return 1000.0 * tcpacket.rt_timer.time(); -} - bool CTranscoderPacket::IsLast() const { return tcpacket.is_last; diff --git a/TranscoderPacket.h b/TranscoderPacket.h index 039f6f0..31ad57a 100644 --- a/TranscoderPacket.h +++ b/TranscoderPacket.h @@ -52,7 +52,6 @@ public: ECodecType GetCodecIn() const; uint16_t GetStreamId() const; uint32_t GetSequence() const; - double GetTimeMS() const; bool IsLast() const; bool IsSecond() const; bool DStarIsSet() const; From c8972f8075224f8512d82b37296e4d6d8c736b3b Mon Sep 17 00:00:00 2001 From: Tom Early Date: Mon, 20 May 2024 14:45:09 -0700 Subject: [PATCH 08/11] recovering from a closed TCP connection --- Controller.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 82c78a7..587fbdd 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -250,17 +250,12 @@ void CController::ReadReflectorThread() { while (keep_running) { + // preemptively check the connection(s)... + tcClient.ReConnect(); + std::queue> queue; // wait up to 100 ms to read something on the unix port - if (tcClient.Receive(queue, 100)) - { - if (tcClient.ReConnect()) - { - std::cerr << "Unrecoverable ERROR! Quitting..." << std::endl; - exit(1); - } - } - + tcClient.Receive(queue, 100); while (! queue.empty()) { // create a shared pointer to a new packet From 5743fc64e485ee78cedf2acee2d66c9c51cab64a Mon Sep 17 00:00:00 2001 From: Tom Early Date: Thu, 23 May 2024 06:40:54 -0700 Subject: [PATCH 09/11] readme --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 21ca73a..9d287c3 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,11 @@ This is the only transcoder that will work with the [URF reflector](https://gith This software is loosely based on LX3JL's **ambed**, but is easily different enough to be considered an entirely original work. Here are some major differences with ambed: - tcd uses both hardware-based and software-based vocoders, providing a bridge between the closed source vocoders used in DStar, DMR NXDN and YSF and open-source vocoders used in M17 (Codec2) and P25 (IMBE). -- *UNIX Sockets* are used to communicate between the reflector and this transcoder. This greatly simplifies the code and significantly improves transcoding performance. +- *TCP Sockets* are used to communicate between the reflector and this transcoder. This guarantees that packets moving between the reflector and transcoder are never lost and the arrive at their destination in order. - Each configured module has a dedicated encoding and decoding instance running on a different thread. This prevents overloading when processing multiple voice streams and provides the best possible performance for the reflector's clients. ## Constraints and Requirements -Currently, this program must be run locally with its paired URF reflector. Remote transcoding is not yet supported. - Only systemd-based operating systems are supported. Debian or Ubuntu is recommended. If you want to install this on a non-systemd based OS, you are on your own. Also, by default, *tcd* is built without gdb support. The P25 IMBE software vocoder library is available [here](https://github.com/nostar/imbe_vocoder). See its README.md file for instructions for compiling and installing this library. @@ -28,14 +26,14 @@ The DVSI devices need an FTDI driver which is available [here](https://ftdichip. ## Download the repository -In the parent directory of you urfd repository: +In the parent directory of you *urfd* repository: ```bash git clone https://github.com/nostar/tcd.git cd tcd ``` -To be perfectly clear, the urfd reflector repository clone and this clone **must be in the same directory**. +To be perfectly clear, the urfd reflector repository clone and this clone **must be in the same directory**. If your transcoder is a remote installation, you still need to `git clone https://github.com/nostar/urfd.git` even though you won't compile anything in the *urfd* repository. Both *tcd* and *urfd* repositories need to be in the same directory as several of the source files in *tcd* are symbolic links to the adjacent *urfd* reflector source code. ## Compiling and configuring *tcd* @@ -47,10 +45,10 @@ cp config/* . Use your favorite text editor to edit the following files: - *tcd.mk* defines some compile time options. If you want to use the md380 vocoder, or change the installation directory, specify it here. Once you've set these options, do `make` to compile *tcd*. If you change `BINDIR`, you need to also change the `ExecStart` in your *tcd.service* file. -- *tcd.ini* defines run-time options. It is especially imporant that the `Transcoded` line for the tcd.ini file is exactly the same as the same line in the urfd.ini file! Suggested values for vocoder gains are provided. +- *tcd.ini* defines run-time options. It is especially important that the `Modules` line for the tcd.ini file is exactly the same as the same line in the urfd.ini file! The `ServerAddress` is the url of the server. If the transcoder is local, this is usually `127.0.0.1` or `::1`. If the transcoder is remote, this is the IP address of the server. Suggested values for vocoder gains are provided. - *tcd.service* is the systemd service file. You will need to modify the `ExecStart` line to successfully start *tcd* by specifying the path to your *tcd* executable and your tcd.ini file. -## Installing *tcd* +## Installing *tcd* when the transcoder is local It is easiest to install and uninstall *tcd* using the ./radmin scripts in your urfd repo. If you want to do this manually: @@ -58,3 +56,18 @@ It is easiest to install and uninstall *tcd* using the ./radmin scripts in your sudo make install sudo make uninstall ``` + +## Installing *tcd when the transcoder is remote + +Use: +- `make` to compile *tcd*. +- `sudo make install` to install and run *tcd*. +- `sudo systemctl *something*` is used to manage the running *tcd*, where `*something*` might be `start`, `stop` or other verbs. +- `sudo journalctl -u tcd -f` to monitor the logs. +- `sudo make uninstall` to uninstall *tcd*. + +## Other considerations + +The TCP connection(s) are designed to reestablish themselves quickly if broken or otherwise interrupted. In some cases the interruption will cause either *tcd* or *urfd* to abort, but in some cases the module activity will block until the TCP connections are reestablished. But if the interruption is lengthy (more than a few seconds), clients using a transcoded reflector module will have trouble with the interruption. + +If the TCP connection(s) bewteen *tcd* and *urfd* are lost,tThe TCP connections will make every effort to reestablish the TCP ports. Once the port(s) have been reopened, packets queued up on the reflector will be sent to tcd as received, so if the TCP disconnect time is more that a second or two there could be a significant delay from went a user transmits into the reflector module, and when other clients listening to that module actually hear the transmission. If the TCP ports are down for a significant time, it's probably best to restart both the reflector and transcoder. From 772e87d647336ae4a50580a066968aa53b23dee6 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Fri, 24 May 2024 06:10:06 -0700 Subject: [PATCH 10/11] return type for ReConnect --- Controller.cpp | 6 +----- README.md | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 587fbdd..ea0e966 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -603,11 +603,7 @@ void CController::SendToReflector(std::shared_ptr packet) // send the packet over the socket while (tcClient.Send(packet->GetTCPacket())) { - if (tcClient.ReConnect()) - { - std::cerr << "Unrecoverable ERROR, quiting!" << std::endl; - exit(1); - } + tcClient.ReConnect(); } packet->Sent(); } diff --git a/README.md b/README.md index 9d287c3..b5295fa 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,4 @@ Use: - `sudo journalctl -u tcd -f` to monitor the logs. - `sudo make uninstall` to uninstall *tcd*. -## Other considerations - -The TCP connection(s) are designed to reestablish themselves quickly if broken or otherwise interrupted. In some cases the interruption will cause either *tcd* or *urfd* to abort, but in some cases the module activity will block until the TCP connections are reestablished. But if the interruption is lengthy (more than a few seconds), clients using a transcoded reflector module will have trouble with the interruption. - -If the TCP connection(s) bewteen *tcd* and *urfd* are lost,tThe TCP connections will make every effort to reestablish the TCP ports. Once the port(s) have been reopened, packets queued up on the reflector will be sent to tcd as received, so if the TCP disconnect time is more that a second or two there could be a significant delay from went a user transmits into the reflector module, and when other clients listening to that module actually hear the transmission. If the TCP ports are down for a significant time, it's probably best to restart both the reflector and transcoder. +When started, *tcd* will establish a TCP connection for each transcoded reflector module. If the TCP connection is lost, *tcds* will block until the connection is reestablished. A message will be printed every 10 seconds suggesting that the reflector needs to be restarted. From 9fae066d8019aa99d791670d64d348b3db539bfc Mon Sep 17 00:00:00 2001 From: Tom Early Date: Wed, 26 Jun 2024 10:24:55 -0700 Subject: [PATCH 11/11] reademe --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5295fa..00525e4 100644 --- a/README.md +++ b/README.md @@ -66,4 +66,4 @@ Use: - `sudo journalctl -u tcd -f` to monitor the logs. - `sudo make uninstall` to uninstall *tcd*. -When started, *tcd* will establish a TCP connection for each transcoded reflector module. If the TCP connection is lost, *tcds* will block until the connection is reestablished. A message will be printed every 10 seconds suggesting that the reflector needs to be restarted. +When started, *tcd* will establish a TCP connection for each transcoded reflector module. If the TCP connection is lost, *tcd* will block until the connection is reestablished. A message will be printed every 10 seconds suggesting that the reflector needs to be restarted.