From 0e940f117e0a66e91213519917960f684719bf9e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 11 Mar 2022 17:42:58 +0100 Subject: [PATCH] #20 audio Unit now also using ambe fiel reader --- .vscode/tasks.json | 10 +- Common/AudioUnit.cpp | 368 +++++++++++++------------------------------ Common/AudioUnit.h | 47 +----- 3 files changed, 118 insertions(+), 307 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0545c42..587d251 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -26,7 +26,10 @@ "USE_GPSD=1", "DStarGateway/dstargateway" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -65,10 +68,7 @@ "USE_GPSD=1", "DGWTimeServer/dgwtimeserver" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { diff --git a/Common/AudioUnit.cpp b/Common/AudioUnit.cpp index 66684a0..997acc9 100644 --- a/Common/AudioUnit.cpp +++ b/Common/AudioUnit.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "DStarDefines.h" #include "HeaderData.h" @@ -30,9 +31,8 @@ #include "Utils.h" #include "Log.h" -unsigned char* CAudioUnit::m_ambe = NULL; -unsigned int CAudioUnit::m_ambeLength = 0U; -std::map CAudioUnit::m_index; + +CAMBEFileReader * CAudioUnit::m_ambeFilereader = nullptr; TEXT_LANG CAudioUnit::m_language = TL_ENGLISH_UK; @@ -46,6 +46,11 @@ void CAudioUnit::initialise() void CAudioUnit::setLanguage(const std::string & dir, TEXT_LANG language) { + if(m_ambeFilereader != nullptr) { + delete m_ambeFilereader; + m_ambeFilereader = nullptr; + } + m_language = language; std::string ambeFileName; @@ -94,32 +99,22 @@ void CAudioUnit::setLanguage(const std::string & dir, TEXT_LANG language) break; } - bool ret = readAMBE(dir, ambeFileName); - if (!ret) { - delete[] m_ambe; - m_ambe = NULL; - return; - } - - ret = readIndex(dir, indxFileName); - if (!ret) { - delete[] m_ambe; - m_ambe = NULL; + m_ambeFilereader = new CAMBEFileReader(dir + "/" + indxFileName, dir + "/" + ambeFileName); + bool ret = m_ambeFilereader->read(); + if(!ret) { + delete m_ambeFilereader; + m_ambeFilereader = nullptr; } } void CAudioUnit::finalise() { - for (std::map::iterator it = m_index.begin(); it != m_index.end(); ++it) - delete it->second; - - delete[] m_ambe; + delete m_ambeFilereader; } CAudioUnit::CAudioUnit(IRepeaterCallback* handler, const std::string& callsign) : m_handler(handler), m_callsign(callsign), -m_encoder(), m_status(AS_IDLE), m_linkStatus(LS_NONE), m_tempLinkStatus(LS_NONE), @@ -129,28 +124,24 @@ m_reflector(), m_tempReflector(), m_hasTemporary(false), m_timer(1000U, REPLY_TIME), -m_data(NULL), -m_in(0U), -m_out(0U), -m_seqNo(0U) //, +m_data(), +m_out(0U) //m_time() { assert(handler != NULL); - - m_data = new CAMBEData*[MAX_FRAMES]; - - for (unsigned int i = 0U; i < MAX_FRAMES; i++) - m_data[i] = NULL; } CAudioUnit::~CAudioUnit() { - delete[] m_data; + for (auto item : m_data) { + delete item; + } + m_data.clear(); } void CAudioUnit::sendStatus() { - if (m_ambe == NULL) + if (m_ambeFilereader == nullptr) return; if (m_status != AS_IDLE) @@ -190,7 +181,6 @@ void CAudioUnit::clock(unsigned int ms) m_timer.stop(); m_out = 0U; - m_seqNo = 0U; m_status = AS_TRANSMIT; m_time = std::chrono::high_resolution_clock::now(); @@ -199,29 +189,21 @@ void CAudioUnit::clock(unsigned int ms) } if (m_status == AS_TRANSMIT) { - std::chrono::high_resolution_clock::time_point hrctp = std::chrono::high_resolution_clock::now(); - auto elapse = std::chrono::duration_cast(hrctp - m_time); - unsigned int needed = elapse.count() / DSTAR_FRAME_TIME_MS; + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + unsigned int needed = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_time).count(); + needed /= DSTAR_FRAME_TIME_MS; - while (m_out < needed) { + while (m_out < needed && m_out < m_data.size()) { CAMBEData* data = m_data[m_out]; - m_data[m_out] = NULL; m_out++; - - if (m_in == m_out) - data->setEnd(true); - + CLog::logTrace("m_out %u, needed %u, m_data %u", m_out, needed, m_data.size()); m_handler->process(*data, DIR_INCOMING, AS_INFO); + } - delete data; - - if (m_in == m_out) { - m_in = 0U; - m_out = 0U; - m_status = AS_IDLE; - m_timer.stop(); - return; - } + if (m_out >= m_data.size()) { + m_out = 0U; + m_status = AS_IDLE; + m_timer.stop(); } return; @@ -230,63 +212,14 @@ void CAudioUnit::clock(unsigned int ms) void CAudioUnit::cancel() { - for (unsigned int i = 0U; i < MAX_FRAMES; i++) { - if (m_data[i] != NULL) { - delete m_data[i]; - m_data[i] = NULL; - } - } - + CLog::logTrace("Audio Unit Cancel"); m_status = AS_IDLE; m_out = 0U; - m_in = 0U; m_timer.stop(); } -bool CAudioUnit::lookup(unsigned int id, const std::string &name) -{ - CIndexRecord* info = m_index[name]; - if (info == NULL) { - // CLog::logError("Cannot find the AMBE index for *%s*", name.c_str()); - return false; - } - - unsigned int start = info->getStart(); - unsigned int length = info->getLength(); - - for (unsigned int i = 0U; i < length; i++) { - unsigned char* dataIn = m_ambe + (start + i) * VOICE_FRAME_LENGTH_BYTES; - - CAMBEData* dataOut = new CAMBEData; - dataOut->setSeq(m_seqNo); - dataOut->setId(id); - - unsigned char buffer[DV_FRAME_LENGTH_BYTES]; - memcpy(buffer + 0U, dataIn, VOICE_FRAME_LENGTH_BYTES); - - // Insert sync bytes when the sequence number is zero, slow data otherwise - if (m_seqNo == 0U) { - memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); - m_encoder.sync(); - } else { - m_encoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES); - } - - dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES); - - m_seqNo++; - if (m_seqNo == 21) - m_seqNo = 0; - - m_data[m_in] = dataOut; - m_in++; - } - - return true; -} - -void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector) +void CAudioUnit::spellReflector(const std::string &reflector) { unsigned int length = reflector.size(); @@ -294,11 +227,10 @@ void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector) std::string c = reflector.substr(i, 1); if (c.compare(" ")) - lookup(id, c); + m_ambeFilereader->lookup(c, m_data); } char c = reflector.at(length - 1); - if (c == ' ') return; @@ -306,197 +238,113 @@ void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector) 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); + m_ambeFilereader->lookup(cstr, m_data); return; } switch (c) { case 'A': - lookup(id, "alpha"); + m_ambeFilereader->lookup("alpha", m_data); break; case 'B': - lookup(id, "bravo"); + m_ambeFilereader->lookup("bravo", m_data); break; case 'C': - lookup(id, "charlie"); + m_ambeFilereader->lookup("charlie", m_data); break; case 'D': - lookup(id, "delta"); + m_ambeFilereader->lookup("delta", m_data); break; default: - lookup(id, cstr); + m_ambeFilereader->lookup(cstr, m_data); break; } } -bool CAudioUnit::readAMBE(const std::string& dir, const std::string& name) +void CAudioUnit::sendStatus(LINK_STATUS status, const std::string& reflector, const std::string &text) { - std::string fileName = dir + "/" + name; - struct stat sbuf; - - if (stat(fileName.c_str(), &sbuf)) { - CLog::logInfo("File %s not readable\n", fileName.c_str()); - fileName.append("/data/"); - fileName += name; - if (stat(fileName.c_str(), &sbuf)) { - CLog::logInfo("File %s not readable\n", fileName.c_str()); - return false; - } - } - unsigned int fsize = sbuf.st_size; - - FILE *file = fopen(fileName.c_str(), "rb"); - if (NULL == file) { - CLog::logInfo("Cannot open %s for reading\n", fileName.c_str()); - return false; - } - - CLog::logInfo("Reading %s\n", fileName.c_str()); - - unsigned char buffer[VOICE_FRAME_LENGTH_BYTES]; - - size_t n = fread(buffer, sizeof(unsigned char), 4, file); - if (n != 4) { - CLog::logError("Unable to read the header from %s\n", fileName.c_str()); - fclose(file); - return false; - } + CLog::logTrace("Audio Unit sendStatus"); - if (memcmp(buffer, "AMBE", 4)) { - CLog::logError("Invalid header from %s\n", fileName.c_str()); - fclose(file); - return false; + // do some clean up, delete old message + for (auto item : m_data) { + delete item; } + m_data.clear(); - // Length of the file minus the header - unsigned int length = fsize - 4U; - - // Hold the file data plus silence at the end - m_ambe = new unsigned char[length + SILENCE_LENGTH * VOICE_FRAME_LENGTH_BYTES]; - m_ambeLength = 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, 1, length, file); - if (n != length) { - CLog::logError("Unable to read the AMBE data from %s\n", fileName.c_str()); - fclose(file); - delete[] m_ambe; - m_ambe = NULL; - return false; - } + // Create the message + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); - fclose(file); + bool found; - return true; -} - -bool CAudioUnit::readIndex(const std::string& dir, const std::string& name) -{ - std::string fileName = dir + "/" + name; - struct stat sbuf; - - if (stat(fileName.c_str(), &sbuf)) { - CLog::logInfo("File %s not readable\n", fileName.c_str()); - fileName.append("/data/"); - fileName += name; - if (stat(fileName.c_str(), &sbuf)) { - CLog::logInfo("File %s not readable\n", fileName.c_str()); - return false; - } - } - - FILE *file = fopen(fileName.c_str(), "r"); - if (NULL == file) { - CLog::logInfo("Cannot open %s for reading\n", fileName.c_str()); - return false; + switch (status) { + case LS_NONE: + m_ambeFilereader->lookup("notlinked", m_data); + break; + case LS_LINKED_CCS: + case LS_LINKED_DCS: + case LS_LINKED_DPLUS: + case LS_LINKED_DEXTRA: + case LS_LINKED_LOOPBACK: + found = m_ambeFilereader->lookup("linkedto", m_data); + if (!found) { + m_ambeFilereader->lookup("linked", m_data); + m_ambeFilereader->lookup("2", m_data); + } + spellReflector(reflector); + break; + default: + found = m_ambeFilereader->lookup("linkingto", m_data); + if (!found) { + m_ambeFilereader->lookup("linking", m_data); + m_ambeFilereader->lookup("2", m_data); + } + spellReflector(reflector); + break; } - // Add a silence entry at the beginning - m_index[" "] = new CIndexRecord(" ", 0, SILENCE_LENGTH); + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); + m_ambeFilereader->lookup(" ", m_data); - CLog::logInfo("Reading %s\n", fileName.c_str()); + unsigned int id = CHeaderData::createId(); + // RPT1 and RPT2 will be filled in later + CHeaderData header; + header.setMyCall1(m_callsign); + header.setMyCall2("INFO"); + header.setYourCall("CQCQCQ "); + header.setId(id); - char line[128]; - while (fgets(line, 128, file)) { + CSlowDataEncoder slowDataEncoder; + slowDataEncoder.setTextData(text); + unsigned int seqNo = 0U; - if (strlen(line) && '#'!=line[0]) { - const std::string space(" \t\r\n"); - std::string name(strtok(line, space.c_str())); - std::string strt(strtok(NULL, space.c_str())); - std::string leng(strtok(NULL, space.c_str())); + // add the slow data, id, seq num etc ... + for(unsigned int i = 0U; i < m_data.size(); i++) { + m_data[i]->setId(id); + m_data[i]->setSeq(seqNo); - if (name.size() && strt.size() && leng.size()) { - unsigned long start = std::stoul(strt); - unsigned long length = std::stoul(leng); + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + m_data[i]->getData(buffer, DV_FRAME_LENGTH_BYTES); - if (start >= m_ambeLength || (start + length) >= m_ambeLength) - CLog::logInfo("The start or end for *%s* is out of range, start: %lu, end: %lu\n", name.c_str(), start, start + length); - else - m_index[name] = new CIndexRecord(name, start + SILENCE_LENGTH, length); - } + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (seqNo == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + slowDataEncoder.sync(); + } else { + slowDataEncoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); } - } - - fclose(file); - - return true; -} -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; - } + m_data[i]->setData(buffer, DV_FRAME_LENGTH_BYTES); - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); - lookup(id, " "); + seqNo++; + if(seqNo >= 21U) seqNo = 0U; + } - // RPT1 and RPT2 will be filled in later - CHeaderData header; - header.setMyCall1(m_callsign); - header.setMyCall2("INFO"); - header.setYourCall("CQCQCQ "); - header.setId(id); + m_data[m_data.size() - 1]->setEnd(true); - m_handler->process(header, DIR_INCOMING, AS_INFO); + m_handler->process(header, DIR_INCOMING, AS_INFO); } diff --git a/Common/AudioUnit.h b/Common/AudioUnit.h index 6cdd862..7b27ba8 100644 --- a/Common/AudioUnit.h +++ b/Common/AudioUnit.h @@ -23,42 +23,14 @@ #include #include #include +#include #include "RepeaterCallback.h" #include "SlowDataEncoder.h" #include "AMBEData.h" #include "Timer.h" #include "Defs.h" - -class CIndexRecord { -public: - CIndexRecord(const std::string& name, unsigned int start, unsigned int length) : - m_name(name), - m_start(start), - m_length(length) - { - } - - std::string getName() const - { - return m_name; - } - - unsigned int getStart() const - { - return m_start; - } - - unsigned int getLength() const - { - return m_length; - } - -private: - std::string m_name; - unsigned int m_start; - unsigned int m_length; -}; +#include "AMBEFileReader.h" enum AUDIO_STATUS { AS_IDLE, @@ -87,14 +59,10 @@ public: static void finalise(); private: - static std::map m_index; - static unsigned char* m_ambe; - static unsigned int m_ambeLength; static TEXT_LANG m_language; IRepeaterCallback* m_handler; std::string m_callsign; - CSlowDataEncoder m_encoder; AUDIO_STATUS m_status; LINK_STATUS m_linkStatus; LINK_STATUS m_tempLinkStatus; @@ -104,17 +72,12 @@ private: std::string m_tempReflector; bool m_hasTemporary; CTimer m_timer; - CAMBEData** m_data; - unsigned int m_in; + std::vector m_data; + static CAMBEFileReader* m_ambeFilereader; unsigned int m_out; - 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 spellReflector(const std::string& reflector); void sendStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); - - static bool readAMBE(const std::string& dir, const std::string& name); - static bool readIndex(const std::string& dir, const std::string& name); };