#20 audio Unit now also using ambe fiel reader

pull/32/head
Geoffrey Merck 4 years ago
parent e05493633e
commit 0e940f117e

10
.vscode/tasks.json vendored

@ -26,7 +26,10 @@
"USE_GPSD=1", "USE_GPSD=1",
"DStarGateway/dstargateway" "DStarGateway/dstargateway"
], ],
"group": "build", "group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [] "problemMatcher": []
}, },
{ {
@ -65,10 +68,7 @@
"USE_GPSD=1", "USE_GPSD=1",
"DGWTimeServer/dgwtimeserver" "DGWTimeServer/dgwtimeserver"
], ],
"group": { "group": "build",
"kind": "build",
"isDefault": true
},
"problemMatcher": [] "problemMatcher": []
}, },
{ {

@ -23,6 +23,7 @@
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <stdio.h> #include <stdio.h>
#include <thread>
#include "DStarDefines.h" #include "DStarDefines.h"
#include "HeaderData.h" #include "HeaderData.h"
@ -30,9 +31,8 @@
#include "Utils.h" #include "Utils.h"
#include "Log.h" #include "Log.h"
unsigned char* CAudioUnit::m_ambe = NULL;
unsigned int CAudioUnit::m_ambeLength = 0U; CAMBEFileReader * CAudioUnit::m_ambeFilereader = nullptr;
std::map<std::string, CIndexRecord *> CAudioUnit::m_index;
TEXT_LANG CAudioUnit::m_language = TL_ENGLISH_UK; 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) void CAudioUnit::setLanguage(const std::string & dir, TEXT_LANG language)
{ {
if(m_ambeFilereader != nullptr) {
delete m_ambeFilereader;
m_ambeFilereader = nullptr;
}
m_language = language; m_language = language;
std::string ambeFileName; std::string ambeFileName;
@ -94,32 +99,22 @@ void CAudioUnit::setLanguage(const std::string & dir, TEXT_LANG language)
break; break;
} }
bool ret = readAMBE(dir, ambeFileName); m_ambeFilereader = new CAMBEFileReader(dir + "/" + indxFileName, dir + "/" + ambeFileName);
if (!ret) { bool ret = m_ambeFilereader->read();
delete[] m_ambe; if(!ret) {
m_ambe = NULL; delete m_ambeFilereader;
return; m_ambeFilereader = nullptr;
}
ret = readIndex(dir, indxFileName);
if (!ret) {
delete[] m_ambe;
m_ambe = NULL;
} }
} }
void CAudioUnit::finalise() void CAudioUnit::finalise()
{ {
for (std::map<std::string, CIndexRecord *>::iterator it = m_index.begin(); it != m_index.end(); ++it) delete m_ambeFilereader;
delete it->second;
delete[] m_ambe;
} }
CAudioUnit::CAudioUnit(IRepeaterCallback* handler, const std::string& callsign) : CAudioUnit::CAudioUnit(IRepeaterCallback* handler, const std::string& callsign) :
m_handler(handler), m_handler(handler),
m_callsign(callsign), m_callsign(callsign),
m_encoder(),
m_status(AS_IDLE), m_status(AS_IDLE),
m_linkStatus(LS_NONE), m_linkStatus(LS_NONE),
m_tempLinkStatus(LS_NONE), m_tempLinkStatus(LS_NONE),
@ -129,28 +124,24 @@ m_reflector(),
m_tempReflector(), m_tempReflector(),
m_hasTemporary(false), m_hasTemporary(false),
m_timer(1000U, REPLY_TIME), m_timer(1000U, REPLY_TIME),
m_data(NULL), m_data(),
m_in(0U), m_out(0U)
m_out(0U),
m_seqNo(0U) //,
//m_time() //m_time()
{ {
assert(handler != NULL); assert(handler != NULL);
m_data = new CAMBEData*[MAX_FRAMES];
for (unsigned int i = 0U; i < MAX_FRAMES; i++)
m_data[i] = NULL;
} }
CAudioUnit::~CAudioUnit() CAudioUnit::~CAudioUnit()
{ {
delete[] m_data; for (auto item : m_data) {
delete item;
}
m_data.clear();
} }
void CAudioUnit::sendStatus() void CAudioUnit::sendStatus()
{ {
if (m_ambe == NULL) if (m_ambeFilereader == nullptr)
return; return;
if (m_status != AS_IDLE) if (m_status != AS_IDLE)
@ -190,7 +181,6 @@ void CAudioUnit::clock(unsigned int ms)
m_timer.stop(); m_timer.stop();
m_out = 0U; m_out = 0U;
m_seqNo = 0U;
m_status = AS_TRANSMIT; m_status = AS_TRANSMIT;
m_time = std::chrono::high_resolution_clock::now(); m_time = std::chrono::high_resolution_clock::now();
@ -199,29 +189,21 @@ void CAudioUnit::clock(unsigned int ms)
} }
if (m_status == AS_TRANSMIT) { if (m_status == AS_TRANSMIT) {
std::chrono::high_resolution_clock::time_point hrctp = std::chrono::high_resolution_clock::now(); std::this_thread::sleep_for(std::chrono::milliseconds(20));
auto elapse = std::chrono::duration_cast<std::chrono::milliseconds>(hrctp - m_time); unsigned int needed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_time).count();
unsigned int needed = elapse.count() / DSTAR_FRAME_TIME_MS; needed /= DSTAR_FRAME_TIME_MS;
while (m_out < needed) { while (m_out < needed && m_out < m_data.size()) {
CAMBEData* data = m_data[m_out]; CAMBEData* data = m_data[m_out];
m_data[m_out] = NULL;
m_out++; m_out++;
CLog::logTrace("m_out %u, needed %u, m_data %u", m_out, needed, m_data.size());
if (m_in == m_out)
data->setEnd(true);
m_handler->process(*data, DIR_INCOMING, AS_INFO); m_handler->process(*data, DIR_INCOMING, AS_INFO);
}
delete data; if (m_out >= m_data.size()) {
m_out = 0U;
if (m_in == m_out) { m_status = AS_IDLE;
m_in = 0U; m_timer.stop();
m_out = 0U;
m_status = AS_IDLE;
m_timer.stop();
return;
}
} }
return; return;
@ -230,63 +212,14 @@ void CAudioUnit::clock(unsigned int ms)
void CAudioUnit::cancel() void CAudioUnit::cancel()
{ {
for (unsigned int i = 0U; i < MAX_FRAMES; i++) { CLog::logTrace("Audio Unit Cancel");
if (m_data[i] != NULL) {
delete m_data[i];
m_data[i] = NULL;
}
}
m_status = AS_IDLE; m_status = AS_IDLE;
m_out = 0U; m_out = 0U;
m_in = 0U;
m_timer.stop(); m_timer.stop();
} }
bool CAudioUnit::lookup(unsigned int id, const std::string &name) void CAudioUnit::spellReflector(const std::string &reflector)
{
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)
{ {
unsigned int length = reflector.size(); 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); std::string c = reflector.substr(i, 1);
if (c.compare(" ")) if (c.compare(" "))
lookup(id, c); m_ambeFilereader->lookup(c, m_data);
} }
char c = reflector.at(length - 1); char c = reflector.at(length - 1);
if (c == ' ') if (c == ' ')
return; return;
@ -306,197 +238,113 @@ void CAudioUnit::spellReflector(unsigned int id, const std::string &reflector)
cstr.push_back(c); cstr.push_back(c);
if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS || if (m_linkStatus == LS_LINKING_DCS || m_linkStatus == LS_LINKED_DCS ||
m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) { m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) {
lookup(id, cstr); m_ambeFilereader->lookup(cstr, m_data);
return; return;
} }
switch (c) { switch (c) {
case 'A': case 'A':
lookup(id, "alpha"); m_ambeFilereader->lookup("alpha", m_data);
break; break;
case 'B': case 'B':
lookup(id, "bravo"); m_ambeFilereader->lookup("bravo", m_data);
break; break;
case 'C': case 'C':
lookup(id, "charlie"); m_ambeFilereader->lookup("charlie", m_data);
break; break;
case 'D': case 'D':
lookup(id, "delta"); m_ambeFilereader->lookup("delta", m_data);
break; break;
default: default:
lookup(id, cstr); m_ambeFilereader->lookup(cstr, m_data);
break; 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; CLog::logTrace("Audio Unit sendStatus");
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;
}
if (memcmp(buffer, "AMBE", 4)) { // do some clean up, delete old message
CLog::logError("Invalid header from %s\n", fileName.c_str()); for (auto item : m_data) {
fclose(file); delete item;
return false;
} }
m_data.clear();
// Length of the file minus the header // Create the message
unsigned int length = fsize - 4U; m_ambeFilereader->lookup(" ", m_data);
m_ambeFilereader->lookup(" ", m_data);
// Hold the file data plus silence at the end m_ambeFilereader->lookup(" ", m_data);
m_ambe = new unsigned char[length + SILENCE_LENGTH * VOICE_FRAME_LENGTH_BYTES]; m_ambeFilereader->lookup(" ", m_data);
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;
}
fclose(file); bool found;
return true; switch (status) {
} case LS_NONE:
m_ambeFilereader->lookup("notlinked", m_data);
bool CAudioUnit::readIndex(const std::string& dir, const std::string& name) break;
{ case LS_LINKED_CCS:
std::string fileName = dir + "/" + name; case LS_LINKED_DCS:
struct stat sbuf; case LS_LINKED_DPLUS:
case LS_LINKED_DEXTRA:
if (stat(fileName.c_str(), &sbuf)) { case LS_LINKED_LOOPBACK:
CLog::logInfo("File %s not readable\n", fileName.c_str()); found = m_ambeFilereader->lookup("linkedto", m_data);
fileName.append("/data/"); if (!found) {
fileName += name; m_ambeFilereader->lookup("linked", m_data);
if (stat(fileName.c_str(), &sbuf)) { m_ambeFilereader->lookup("2", m_data);
CLog::logInfo("File %s not readable\n", fileName.c_str()); }
return false; spellReflector(reflector);
} break;
} default:
found = m_ambeFilereader->lookup("linkingto", m_data);
FILE *file = fopen(fileName.c_str(), "r"); if (!found) {
if (NULL == file) { m_ambeFilereader->lookup("linking", m_data);
CLog::logInfo("Cannot open %s for reading\n", fileName.c_str()); m_ambeFilereader->lookup("2", m_data);
return false; }
spellReflector(reflector);
break;
} }
// Add a silence entry at the beginning m_ambeFilereader->lookup(" ", m_data);
m_index[" "] = new CIndexRecord(" ", 0, SILENCE_LENGTH); 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]; CSlowDataEncoder slowDataEncoder;
while (fgets(line, 128, file)) { slowDataEncoder.setTextData(text);
unsigned int seqNo = 0U;
if (strlen(line) && '#'!=line[0]) { // add the slow data, id, seq num etc ...
const std::string space(" \t\r\n"); for(unsigned int i = 0U; i < m_data.size(); i++) {
std::string name(strtok(line, space.c_str())); m_data[i]->setId(id);
std::string strt(strtok(NULL, space.c_str())); m_data[i]->setSeq(seqNo);
std::string leng(strtok(NULL, space.c_str()));
if (name.size() && strt.size() && leng.size()) { unsigned char buffer[DV_FRAME_LENGTH_BYTES];
unsigned long start = std::stoul(strt); m_data[i]->getData(buffer, DV_FRAME_LENGTH_BYTES);
unsigned long length = std::stoul(leng);
if (start >= m_ambeLength || (start + length) >= m_ambeLength) // Insert sync bytes when the sequence number is zero, slow data otherwise
CLog::logInfo("The start or end for *%s* is out of range, start: %lu, end: %lu\n", name.c_str(), start, start + length); if (seqNo == 0U) {
else ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
m_index[name] = new CIndexRecord(name, start + SILENCE_LENGTH, length); 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_data[i]->setData(buffer, DV_FRAME_LENGTH_BYTES);
{
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, " "); seqNo++;
lookup(id, " "); if(seqNo >= 21U) seqNo = 0U;
lookup(id, " "); }
lookup(id, " ");
// RPT1 and RPT2 will be filled in later m_data[m_data.size() - 1]->setEnd(true);
CHeaderData header;
header.setMyCall1(m_callsign);
header.setMyCall2("INFO");
header.setYourCall("CQCQCQ ");
header.setId(id);
m_handler->process(header, DIR_INCOMING, AS_INFO); m_handler->process(header, DIR_INCOMING, AS_INFO);
} }

@ -23,42 +23,14 @@
#include <string> #include <string>
#include <map> #include <map>
#include <chrono> #include <chrono>
#include <vector>
#include "RepeaterCallback.h" #include "RepeaterCallback.h"
#include "SlowDataEncoder.h" #include "SlowDataEncoder.h"
#include "AMBEData.h" #include "AMBEData.h"
#include "Timer.h" #include "Timer.h"
#include "Defs.h" #include "Defs.h"
#include "AMBEFileReader.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;
};
enum AUDIO_STATUS { enum AUDIO_STATUS {
AS_IDLE, AS_IDLE,
@ -87,14 +59,10 @@ public:
static void finalise(); static void finalise();
private: private:
static std::map<std::string, CIndexRecord *> m_index;
static unsigned char* m_ambe;
static unsigned int m_ambeLength;
static TEXT_LANG m_language; static TEXT_LANG m_language;
IRepeaterCallback* m_handler; IRepeaterCallback* m_handler;
std::string m_callsign; std::string m_callsign;
CSlowDataEncoder m_encoder;
AUDIO_STATUS m_status; AUDIO_STATUS m_status;
LINK_STATUS m_linkStatus; LINK_STATUS m_linkStatus;
LINK_STATUS m_tempLinkStatus; LINK_STATUS m_tempLinkStatus;
@ -104,17 +72,12 @@ private:
std::string m_tempReflector; std::string m_tempReflector;
bool m_hasTemporary; bool m_hasTemporary;
CTimer m_timer; CTimer m_timer;
CAMBEData** m_data; std::vector<CAMBEData*> m_data;
unsigned int m_in; static CAMBEFileReader* m_ambeFilereader;
unsigned int m_out; unsigned int m_out;
unsigned int m_seqNo;
std::chrono::high_resolution_clock::time_point m_time; std::chrono::high_resolution_clock::time_point m_time;
bool lookup(unsigned int id, const std::string& name); void spellReflector(const std::string& reflector);
void spellReflector(unsigned int id, const std::string& reflector);
void sendStatus(LINK_STATUS status, const std::string& reflector, const std::string& text); 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);
}; };

Loading…
Cancel
Save

Powered by TurnKey Linux.