From 6a9ea255b513866f58e272b22ba55a45421ae60d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 15 Mar 2020 08:28:08 +0100 Subject: [PATCH] First audio prototype, still need large cleanup --- AudioUnit.cpp | 321 +++++++++++++++++++++++++++-------------------- AudioUnit.h | 50 +++++--- GroupHandler.cpp | 98 ++++++++------- GroupHandler.h | 10 +- 4 files changed, 282 insertions(+), 197 deletions(-) diff --git a/AudioUnit.cpp b/AudioUnit.cpp index 0330235..f26c23c 100644 --- a/AudioUnit.cpp +++ b/AudioUnit.cpp @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include "DStarDefines.h" #include "HeaderData.h" @@ -36,7 +39,7 @@ TEXT_LANG CAudioUnit::m_language = TL_ENGLISH_UK; const unsigned int MAX_FRAMES = 60U * DSTAR_FRAMES_PER_SEC; -const unsigned int SILENCE_LENGTH = 10U; +const unsigned int SILENCE_LENGTH = 10U;//Number of silence frames void CAudioUnit::initialise() { @@ -114,18 +117,17 @@ void CAudioUnit::finalise() delete[] m_ambe; } -CAudioUnit::CAudioUnit(IRepeaterCallback* handler, const std::string& callsign) : +CAudioUnit::CAudioUnit(CG2ProtocolHandler* handler) : m_handler(handler), -m_callsign(callsign), +// m_callsign(callsign), m_encoder(), m_status(AS_IDLE), -m_linkStatus(LS_NONE), -m_tempLinkStatus(LS_NONE), -m_text(), -m_tempText(), -m_reflector(), -m_tempReflector(), -m_hasTemporary(false), +m_ackType(AT_LOGIN), +m_groupName(), +m_user(), +m_repeater(), +m_gateway(), +m_destination(), m_timer(1000U, REPLY_TIME), m_data(NULL), m_in(0U), @@ -158,19 +160,29 @@ void CAudioUnit::sendStatus() m_timer.start(); } -void CAudioUnit::setStatus(LINK_STATUS status, const std::string& reflector, const std::string& text) +// void CAudioUnit::setStatus(LINK_STATUS status, const std::string& reflector, const std::string& text) +// { +// m_linkStatus = status; +// m_reflector = reflector; +// m_text = text; +// } + +// void CAudioUnit::setTempStatus(LINK_STATUS status, const std::string& reflector, const std::string& text) +// { +// m_tempLinkStatus = status; +// m_tempReflector = reflector; +// m_tempText = text; +// m_hasTemporary = true; +// } + +void CAudioUnit::setAck(ACK_TYPE ackType, const std::string& groupName, const std::string& user, const std::string& repeater, const std::string& gateway, const in_addr& destination) { - m_linkStatus = status; - m_reflector = reflector; - m_text = text; -} - -void CAudioUnit::setTempStatus(LINK_STATUS status, const std::string& reflector, const std::string& text) -{ - m_tempLinkStatus = status; - m_tempReflector = reflector; - m_tempText = text; - m_hasTemporary = true; + m_ackType = ackType; + m_groupName = groupName; + m_user = user; + m_repeater = repeater; + m_gateway = gateway; + m_destination = destination; } void CAudioUnit::clock(unsigned int ms) @@ -178,12 +190,8 @@ void CAudioUnit::clock(unsigned int ms) m_timer.clock(ms); if (m_status == AS_WAIT && m_timer.hasExpired()) { - if (m_hasTemporary) { - sendStatus(m_tempLinkStatus, m_tempReflector, m_tempText); - m_hasTemporary = false; - } else { - sendStatus(m_linkStatus, m_reflector, m_text); - } + + sendAck(m_ackType, m_groupName, m_user, m_repeater, m_gateway, m_destination); m_timer.stop(); @@ -209,7 +217,7 @@ void CAudioUnit::clock(unsigned int ms) if (m_in == m_out) data->setEnd(true); - m_handler->process(*data, DIR_INCOMING, AS_INFO); + m_handler->writeAMBE(*data); delete data; @@ -242,7 +250,7 @@ void CAudioUnit::cancel() m_timer.stop(); } -bool CAudioUnit::lookup(unsigned int id, const std::string &name) +bool CAudioUnit::lookup(unsigned int id, const std::string &name, const in_addr& destination) { CIndexRecord* info = m_index[name]; if (info == NULL) { @@ -259,6 +267,7 @@ bool CAudioUnit::lookup(unsigned int id, const std::string &name) CAMBEData* dataOut = new CAMBEData; dataOut->setSeq(m_seqNo); dataOut->setId(id); + dataOut->setDestination(destination, G2_DV_PORT); unsigned char buffer[DV_FRAME_LENGTH_BYTES]; memcpy(buffer + 0U, dataIn, VOICE_FRAME_LENGTH_BYTES); @@ -284,48 +293,48 @@ bool CAudioUnit::lookup(unsigned int id, const std::string &name) return true; } -void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector) -{ - unsigned int length = reflector.size(); - - for (unsigned int i = 0; i < (length - 1); i++) { - std::string c = reflector.substr(i, 1); - - if (c.compare(" ")) - lookup(id, c); - } - - char c = reflector.at(length - 1); - - if (c == ' ') - return; - - std::string cstr; - cstr.push_back(c); - if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS || - m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) { - lookup(id, cstr); - return; - } - - switch (c) { - case 'A': - lookup(id, "alpha"); - break; - case 'B': - lookup(id, "bravo"); - break; - case 'C': - lookup(id, "charlie"); - break; - case 'D': - lookup(id, "delta"); - break; - default: - lookup(id, cstr); - break; - } -} +// void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector) +// { +// unsigned int length = reflector.size(); + +// for (unsigned int i = 0; i < (length - 1); i++) { +// std::string c = reflector.substr(i, 1); + +// if (c.compare(" ")) +// lookup(id, c); +// } + +// char c = reflector.at(length - 1); + +// if (c == ' ') +// return; + +// std::string cstr; +// cstr.push_back(c); +// if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS || +// m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) { +// lookup(id, cstr); +// return; +// } + +// switch (c) { +// case 'A': +// lookup(id, "alpha"); +// break; +// case 'B': +// lookup(id, "bravo"); +// break; +// case 'C': +// lookup(id, "charlie"); +// break; +// case 'D': +// lookup(id, "delta"); +// break; +// default: +// lookup(id, cstr); +// break; +// } +// } bool CAudioUnit::readAMBE(const std::string& name) { @@ -355,7 +364,7 @@ bool CAudioUnit::readAMBE(const std::string& name) unsigned char buffer[VOICE_FRAME_LENGTH_BYTES]; - size_t n = fread(buffer, 4, 1, file); + size_t n = fread(buffer, 1, 4, file); if (n != 4) { printf("Unable to read the header from %s\n", fileName.c_str()); fclose(file); @@ -368,19 +377,19 @@ bool CAudioUnit::readAMBE(const std::string& name) return false; } - // Length of the file minus the header + // Length of the file minus the header length unsigned int length = fsize - 4U; - // Hold the file data plus silence at the end + // Hold the file data plus silence at the beginning m_ambe = new unsigned char[length + SILENCE_LENGTH * VOICE_FRAME_LENGTH_BYTES]; - m_ambeLength = length / VOICE_FRAME_LENGTH_BYTES; + m_ambeLength = (SILENCE_LENGTH + length) / VOICE_FRAME_LENGTH_BYTES; // Add silence to the beginning of the buffer unsigned char* p = m_ambe; for (unsigned int i = 0U; i < SILENCE_LENGTH; i++, p += VOICE_FRAME_LENGTH_BYTES) memcpy(p, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); - n = fread(p, length, 1, file); + n = fread(p, 1, length, file); if (n != length) { printf("Unable to read the AMBE data from %s\n", fileName.c_str()); fclose(file); @@ -411,8 +420,8 @@ bool CAudioUnit::readIndex(const std::string& name) } } - FILE *file = fopen(fileName.c_str(), "r"); - if (NULL == file) { + std::ifstream file(fileName); + if (!file.is_open()) { printf("Cannot open %s for reading\n", fileName.c_str()); return false; } @@ -422,14 +431,18 @@ bool CAudioUnit::readIndex(const std::string& name) printf("Reading %s\n", fileName.c_str()); - char line[128]; - while (fgets(line, 128, file)) { + std::string line; + while (std::getline(file, line)) { - if (strlen(line) && '#'!=line[0]) { + if (!line.empty() && '#'!=line[0]) { + //ToDo F4FXL 2020-03-14 clean this up + char linec[128]; + strcpy(linec, line.c_str()); const std::string space(" \t\r\n"); - std::string name(strtok(line, space.c_str())); + std::string name(strtok(linec, space.c_str())); std::string strt(strtok(NULL, space.c_str())); std::string leng(strtok(NULL, space.c_str())); + ///End ToDo if (name.size() && strt.size() && leng.size()) { unsigned long start = std::stoul(strt); @@ -443,62 +456,102 @@ bool CAudioUnit::readIndex(const std::string& name) } } - fclose(file); - return true; } -void CAudioUnit::sendStatus(LINK_STATUS status, const std::string& reflector, const std::string &text) +void CAudioUnit::sendAck(ACK_TYPE ackType, const std::string& groupName, const std::string& user, const std::string& repeater, const std::string& gateway, const in_addr& destination) { - m_encoder.setTextData(text); - - // Create the message - unsigned int id = CHeaderData::createId(); - - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); - - bool found; - - switch (status) { - case LS_NONE: - lookup(id, "notlinked"); - break; - case LS_LINKED_CCS: - case LS_LINKED_DCS: -// case LS_LINKED_DPLUS: - case LS_LINKED_DEXTRA: - case LS_LINKED_LOOPBACK: - found = lookup(id, "linkedto"); - if (!found) { - lookup(id, "linked"); - lookup(id, "2"); - } - spellReflector(id, reflector); - break; - default: - found = lookup(id, "linkingto"); - if (!found) { - lookup(id, "linking"); - lookup(id, "2"); - } - spellReflector(id, reflector); - break; - } + unsigned int id = CHeaderData::createId(); + + CHeaderData header(groupName, " ", user, gateway, repeater); + header.setDestination(destination, G2_DV_PORT); + header.setId(id); + + lookup(id, " ", destination); + + switch (ackType) + { + case AT_LOGIN: + m_encoder.setTextData("Logged in"); + lookup(id, "logged-in", destination); + break; + case AT_LOGOFF: + m_encoder.setTextData("Logged in"); + lookup(id, "logged-off", destination); + break; + default: + m_encoder.setTextData("Doh !"); + break; + } + + lookup(id, " ", destination); - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); + spellGroup(id, groupName, destination); - // RPT1 and RPT2 will be filled in later - CHeaderData header; - header.setMyCall1(m_callsign); - header.setMyCall2("INFO"); - header.setYourCall("CQCQCQ "); - header.setId(id); + m_handler->writeHeader(header); +} - m_handler->process(header, DIR_INCOMING, AS_INFO); +void CAudioUnit::spellGroup(unsigned int id, const std::string& groupName, const in_addr& destination) +{ + for(auto it = groupName.begin(); it != groupName.end();it++) + { + std::string cstr; + cstr.push_back(std::tolower((*it))); + lookup(id, cstr, destination); + } } + +// void CAudioUnit::sendStatus(LINK_STATUS status, const std::string& reflector, const std::string &text) +// { +// m_encoder.setTextData(text); + +// // Create the message +// unsigned int id = CHeaderData::createId(); + +// lookup(id, " "); +// lookup(id, " "); +// lookup(id, " "); +// lookup(id, " "); + +// bool found; + +// switch (status) { +// case LS_NONE: +// lookup(id, "notlinked"); +// break; +// case LS_LINKED_CCS: +// case LS_LINKED_DCS: +// // case LS_LINKED_DPLUS: +// case LS_LINKED_DEXTRA: +// case LS_LINKED_LOOPBACK: +// found = lookup(id, "linkedto"); +// if (!found) { +// lookup(id, "linked"); +// lookup(id, "2"); +// } +// spellReflector(id, reflector); +// break; +// default: +// found = lookup(id, "linkingto"); +// if (!found) { +// lookup(id, "linking"); +// lookup(id, "2"); +// } +// spellReflector(id, reflector); +// break; +// } + +// lookup(id, " "); +// lookup(id, " "); +// lookup(id, " "); +// lookup(id, " "); + +// // RPT1 and RPT2 will be filled in later +// CHeaderData header; +// header.setMyCall1(m_callsign); +// header.setMyCall2("INFO"); +// header.setYourCall("CQCQCQ "); +// header.setId(id); + +// m_handler->process(header, DIR_INCOMING, AS_INFO); +// } diff --git a/AudioUnit.h b/AudioUnit.h index cd00570..2b40ac5 100644 --- a/AudioUnit.h +++ b/AudioUnit.h @@ -23,7 +23,7 @@ #include #include -#include "RepeaterCallback.h" +#include "G2ProtocolHandler.h" #include "SlowDataEncoder.h" #include "AMBEData.h" #include "Timer.h" @@ -65,15 +65,23 @@ enum AUDIO_STATUS { AS_TRANSMIT }; +enum ACK_TYPE +{ + AT_LOGIN, + AT_LOGOFF +}; + class CAudioUnit { public: - CAudioUnit(IRepeaterCallback* handler, const std::string& callsign); + CAudioUnit(CG2ProtocolHandler* handler); ~CAudioUnit(); void sendStatus(); - void setStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); - void setTempStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); + // void setStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); + // void setTempStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); + + void setAck(ACK_TYPE ackType, const std::string& groupeName, const std::string& user, const std::string& repeater, const std::string& gateway, const in_addr& destination); void cancel(); @@ -90,18 +98,23 @@ private: static unsigned char* m_ambe; static unsigned int m_ambeLength; static TEXT_LANG m_language; - - IRepeaterCallback* m_handler; - std::string m_callsign; + CG2ProtocolHandler* m_handler; + //std::string m_callsign; CSlowDataEncoder m_encoder; AUDIO_STATUS m_status; - LINK_STATUS m_linkStatus; - LINK_STATUS m_tempLinkStatus; - std::string m_text; - std::string m_tempText; - std::string m_reflector; - std::string m_tempReflector; - bool m_hasTemporary; + ACK_TYPE m_ackType; + std::string m_groupName; + std::string m_user; + std::string m_repeater; + std::string m_gateway; + in_addr m_destination; + // LINK_STATUS m_linkStatus; + // LINK_STATUS m_tempLinkStatus; + // std::string m_text; + // std::string m_tempText; + // std::string m_reflector; + // std::string m_tempReflector; + // bool m_hasTemporary; CTimer m_timer; CAMBEData** m_data; unsigned int m_in; @@ -109,9 +122,12 @@ private: unsigned int m_seqNo; std::chrono::high_resolution_clock::time_point m_time; - bool lookup(unsigned int id, const std::string& name); - void spellReflector(unsigned int id, const std::string& reflector); - void sendStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); + bool lookup(unsigned int id, const std::string& name, const in_addr& destination); + // void spellReflector(unsigned int id, const std::string& reflector); + // void sendStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); + + void sendAck(ACK_TYPE ackType, const std::string& groupeName, const std::string& user, const std::string& repeater, const std::string& gateway, const in_addr& destination); + void spellGroup(unsigned int id, const std::string& groupName, const in_addr& destination); static bool readAMBE(const std::string& name); static bool readIndex(const std::string& name); diff --git a/GroupHandler.cpp b/GroupHandler.cpp index b3feef8..af6585e 100644 --- a/GroupHandler.cpp +++ b/GroupHandler.cpp @@ -302,6 +302,7 @@ m_linkGateway(), m_linkStatus(LS_NONE), m_oldlinkStatus(LS_INIT), m_linkTimer(1000U, NETWORK_TIMEOUT), +m_audioUnit(NULL), m_id(0x00U), m_announceTimer(1000U, 2U * 60U), // 2 minutes m_userTimeout(userTimeout), @@ -823,6 +824,10 @@ bool CGroupHandler::linkInt() void CGroupHandler::clockInt(unsigned int ms) { + if(m_audioUnit != NULL) + { + m_audioUnit->clock(ms); + } m_linkTimer.clock(ms); if (m_linkTimer.isRunning() && m_linkTimer.hasExpired()) { m_linkTimer.stop(); @@ -857,11 +862,12 @@ void CGroupHandler::clockInt(unsigned int ms) CUserData* user = m_cache->findUser(callsign); if (user) { if (tx->isLogin()) { - sendAck(*user, "Logged in"); + sendAck(*user, AT_LOGIN); } else if (tx->isInfo()) { - sendAck(*user, m_infoText); + //TODO F4FXL 2020-03-15 Audio Info ? + //sendAck(*user, m_infoText); } else if (tx->isLogoff()) { - sendAck(*user, "Logged off"); + sendAck(*user, AT_LOGOFF); } delete user; @@ -1051,48 +1057,54 @@ void CGroupHandler::sendFromText(const std::string &my) const } } -void CGroupHandler::sendAck(const CUserData &user, const std::string &text) const +void CGroupHandler::sendAck(const CUserData &user, ACK_TYPE ackType) { - unsigned int id = CHeaderData::createId(); - - CHeaderData header(m_groupCallsign, " ", user.getUser(), user.getGateway(), user.getRepeater()); - header.setDestination(user.getAddress(), G2_DV_PORT); - header.setId(id); - m_g2Handler->writeHeader(header); - - CSlowDataEncoder slowData; - slowData.setTextData(text); - - CAMBEData data; - data.setId(id); - data.setDestination(user.getAddress(), G2_DV_PORT); - - unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; - ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); - - for (unsigned int i = 0U; i < 20U; i++) { - if (i == 0U) { - // The first AMBE packet is a sync - ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); - data.setData(buffer, DV_FRAME_LENGTH_BYTES); - data.setSeq(i); - } else if (i == 19U) { - // The last packet of the ack - ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); - data.setData(buffer, DV_FRAME_MAX_LENGTH_BYTES); - data.setSeq(i); - data.setEnd(true); - } else { - // The packets containing the text data - unsigned char slowDataBuffer[DATA_FRAME_LENGTH_BYTES]; - slowData.getTextData(slowDataBuffer); - ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, slowDataBuffer, DATA_FRAME_LENGTH_BYTES); - data.setData(buffer, DV_FRAME_LENGTH_BYTES); - data.setSeq(i); - } - - m_g2Handler->writeAMBE(data); + if(m_audioUnit == NULL) + { + m_audioUnit = new CAudioUnit(m_g2Handler); } + m_audioUnit->setAck(ackType, m_groupCallsign, user.getUser(), user.getRepeater(), user.getGateway(), user.getAddress()); + m_audioUnit->sendStatus(); + // unsigned int id = CHeaderData::createId(); + + // CHeaderData header(m_groupCallsign, " ", user.getUser(), user.getGateway(), user.getRepeater()); + // header.setDestination(user.getAddress(), G2_DV_PORT); + // header.setId(id); + // m_g2Handler->writeHeader(header); + + // CSlowDataEncoder slowData; + // slowData.setTextData(text); + + // CAMBEData data; + // data.setId(id); + // data.setDestination(user.getAddress(), G2_DV_PORT); + + // unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES]; + // ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // for (unsigned int i = 0U; i < 20U; i++) { + // if (i == 0U) { + // // The first AMBE packet is a sync + // ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + // data.setData(buffer, DV_FRAME_LENGTH_BYTES); + // data.setSeq(i); + // } else if (i == 19U) { + // // The last packet of the ack + // ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, END_PATTERN_BYTES, END_PATTERN_LENGTH_BYTES); + // data.setData(buffer, DV_FRAME_MAX_LENGTH_BYTES); + // data.setSeq(i); + // data.setEnd(true); + // } else { + // // The packets containing the text data + // unsigned char slowDataBuffer[DATA_FRAME_LENGTH_BYTES]; + // slowData.getTextData(slowDataBuffer); + // ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, slowDataBuffer, DATA_FRAME_LENGTH_BYTES); + // data.setData(buffer, DV_FRAME_LENGTH_BYTES); + // data.setSeq(i); + // } + + // m_g2Handler->writeAMBE(data); + // } } void CGroupHandler::linkUp(DSTAR_PROTOCOL, const std::string &callsign) diff --git a/GroupHandler.h b/GroupHandler.h index 6aca72e..37b509d 100644 --- a/GroupHandler.h +++ b/GroupHandler.h @@ -36,6 +36,7 @@ #include "AMBEData.h" #include "IRCDDB.h" #include "Timer.h" +#include "AudioUnit.h" enum LOGUSER { LU_ON, @@ -93,7 +94,7 @@ private: bool m_info; bool m_logoff; bool m_end; - CSGSXLUser *m_user; + CSGSXLUser *m_user; CTextCollector m_textCollector; }; @@ -105,7 +106,8 @@ public: in_addr m_address; }; -class CGroupHandler : public IReflectorCallback { +class CGroupHandler : public IReflectorCallback, IRepeaterCallback +{ public: static void add(const std::string &callsign, const std::string &logoff, const std::string &repeater, const std::string &infoText, const std::string &permanent, unsigned int userTimeout, CALLSIGN_SWITCH callsignSwitch, bool txMsgSwitch, const std::string & eflector); @@ -179,6 +181,8 @@ private: CTimer m_linkTimer; DSTAR_LINKTYPE m_linkType; + CAudioUnit *m_audioUnit; + unsigned int m_id; CTimer m_announceTimer; unsigned int m_userTimeout; @@ -192,6 +196,6 @@ private: void sendFromText(const std::string &text) const; void sendToRepeaters(CHeaderData &header) const; void sendToRepeaters(CAMBEData &data) const; - void sendAck(const CUserData &user, const std::string &text) const; + void sendAck(const CUserData &user, ACK_TYPE ackType); void logUser(LOGUSER lu, const std::string channel, const std::string user); };