#20 using AmbeFilReader

pull/32/head
Geoffrey Merck 4 years ago
parent d31ecf63c0
commit c8ec37bd85

10
.vscode/tasks.json vendored

@ -65,7 +65,10 @@
"USE_GPSD=1",
"DGWTimeServer/dgwtimeserver"
],
"group": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
},
{
@ -91,10 +94,7 @@
"ENABLE_DEBUG=1",
"USE_GPSD=1"
],
"group": {
"kind": "build",
"isDefault": true
},
"group": "build",
"problemMatcher": []
}
]

@ -107,10 +107,9 @@ bool CTimeServerConfig::loadTimeServer(const CConfig & cfg)
ret = cfg.getValue("timeserver", "address", m_timeServer.address, 0, 1024, "127.0.0.1") && ret;
std::string format;
ret = cfg.getValue("timeserver", "format", format, "voiceandtext", {"voice", "text", "voiceandtext"}) && ret;
ret = cfg.getValue("timeserver", "format", format, "voice", {"voice", "text" }) && ret;
if(format == "voice") m_timeServer.format = FORMAT_VOICE_TIME;
else if(format == "text") m_timeServer.format = FORMAT_TEXT_TIME;
else if(format == "voiceandtext") m_timeServer.format = FORMAT_VOICE_ALL;
std::string lang;
ret = cfg.getValue("timeserver", "language", lang, "english_uk_1", {"english_uk_1", "english_uk_2", "english_us_1", "english_us_2", "deutsch_1", "deutsch_2", "francais", "nederlands", "svenska", "espanol", "norsk", "portugues"}) && ret;;

@ -44,6 +44,5 @@ enum INTERVAL {
enum FORMAT {
FORMAT_VOICE_TIME,
FORMAT_VOICE_ALL,
FORMAT_TEXT_TIME
};

@ -46,32 +46,23 @@ m_addressStr(),
m_language(LANG_ENGLISH_UK_1),
m_format(FORMAT_VOICE_TIME),
m_interval(INTERVAL_15MINS),
m_ambe(NULL),
m_ambeLength(0U),
m_index(),
m_seqNo(0U),
m_in(0U),
m_encoder(),
m_data(NULL),
m_data(),
m_killed(false),
m_dataPath("")
m_dataPath(""),
m_ambeFileReader(nullptr)
{
CHeaderData::initialise();
m_address.s_addr = INADDR_NONE;
m_data = new CAMBEData*[MAX_FRAMES];
for (unsigned int i = 0U; i < MAX_FRAMES; i++)
m_data[i] = nullptr;
m_address.s_addr = INADDR_NONE;
}
CTimeServerThread::~CTimeServerThread()
{
for (auto it = m_index.begin(); it != m_index.end(); it++)
delete it->second;
for(auto d : m_data)
delete d;
delete[] m_ambe;
delete[] m_data;
m_data.clear();
delete[] m_ambeFileReader;
}
void * CTimeServerThread::Entry()
@ -158,8 +149,8 @@ bool CTimeServerThread::setGateway(const std::string& callsign, const std::strin
m_callsign.push_back(' ');
m_addressStr.assign(address);
m_address = CUDPReaderWriter::lookup(address);
m_dataPath.assign(dataPath);
m_address = CUDPReaderWriter::lookup(address);
return true;
}
@ -988,197 +979,103 @@ bool CTimeServerThread::loadAMBE()
break;
}
bool ret = readAMBE(m_dataPath, ambeFileName);
if (!ret) {
delete[] m_ambe;
m_ambe = NULL;
return false;
}
m_ambeFileReader = new CAMBEFileReader(m_dataPath + "/" + indxFileName, m_dataPath + "/" + ambeFileName);
bool ret = m_ambeFileReader->read();
ret = readIndex(m_dataPath, indxFileName);
if (!ret) {
delete[] m_ambe;
m_ambe = NULL;
delete[] m_ambeFileReader;
m_ambeFileReader = nullptr;
return false;
}
return true;
}
bool CTimeServerThread::readAMBE(const std::string& dir, const std::string& name)
void CTimeServerThread::buildAudio(const std::vector<std::string>& words, CSlowDataEncoder& slowDataEncoder)
{
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 int seqNo = 0U;
unsigned char buffer[VOICE_FRAME_LENGTH_BYTES];
m_data.clear();
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(words.size() == 0U || m_ambeFileReader == nullptr)
CLog::logWarning("No words, falling back to text only");
if (memcmp(buffer, "AMBE", 4)) {
CLog::logError("Invalid header from %s\n", fileName.c_str());
fclose(file);
return false;
}
if(m_format == FORMAT_VOICE_TIME && words.size() != 0U) {
// Build the audio
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
// Length of the file minus the header
unsigned int length = fsize - 4U;
for (unsigned int i = 0U; i < words.size(); i++)
m_ambeFileReader->lookup(words.at(i), m_data);
// 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;
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
m_ambeFileReader->lookup(" ", m_data);
// 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);
for(unsigned int i = 0U; i < m_data.size(); i++) {
m_data[i]->setDestination(m_address, G2_DV_PORT);
m_data[i]->setSeq(seqNo);
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;
}
unsigned char buffer[DV_FRAME_LENGTH_BYTES];
m_data[i]->getData(buffer, DV_FRAME_LENGTH_BYTES);
fclose(file);
// 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);
}
return true;
}
m_data[i]->setData(buffer, DV_FRAME_LENGTH_BYTES);
bool CTimeServerThread::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;
seqNo++;
if(seqNo >= 21U) seqNo = 0U;
}
}
else {
for (unsigned int i = 0U; i < 21U; i++, seqNo++) {
CAMBEData* dataOut = new CAMBEData;
unsigned char buffer[DV_FRAME_LENGTH_BYTES];
dataOut->setDestination(m_address, G2_DV_PORT);
dataOut->setSeq(i);
FILE *file = fopen(fileName.c_str(), "r");
if (NULL == file) {
CLog::logInfo("Cannot open %s for reading\n", fileName.c_str());
return false;
}
// Add a silence entry at the beginning
m_index[" "] = new CIndexRecord(" ", 0, SILENCE_LENGTH);
CLog::logInfo("Reading %s\n", fileName.c_str());
char line[128];
while (fgets(line, 128, file)) {
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()));
if (name.size() && strt.size() && leng.size()) {
unsigned long start = std::stoul(strt);
unsigned long length = std::stoul(leng);
::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_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 (i == 0U) {
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
slowDataEncoder.sync();
} else {
slowDataEncoder.getTextData(buffer + VOICE_FRAME_LENGTH_BYTES);
}
}
}
fclose(file);
return true;
}
bool CTimeServerThread::lookup(const std::string &id)
{
CIndexRecord* info = m_index[id];
if (info == NULL) {
// wxLogError(("Cannot find the AMBE index for *%s*"), id.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->setDestination(m_address, G2_DV_PORT);
dataOut->setSeq(m_seqNo);
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();
dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES);
} else {
m_encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES);
m_data.push_back(dataOut);
}
dataOut->setData(buffer, DV_FRAME_LENGTH_BYTES);
m_seqNo++;
if (m_seqNo == 21U)
m_seqNo = 0U;
m_data[m_in] = dataOut;
m_in++;
}
return true;
}
if(seqNo >= 21U) {
seqNo = 0U;
}
void CTimeServerThread::end()
{
CAMBEData* dataOut = new CAMBEData;
dataOut->setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES);
dataOut->setDestination(m_address, G2_DV_PORT);
dataOut->setSeq(m_seqNo);
dataOut->setSeq(seqNo);
dataOut->setEnd(true);
m_data[m_in] = dataOut;
m_in++;
m_data.push_back(dataOut);
}
bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int hour, unsigned int min)
{
CSlowDataEncoder encoder;
CHeaderData header;
header.setMyCall1(m_callsign);
header.setRptCall1(m_callsignG);
@ -1241,78 +1138,26 @@ bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int
break;
}
m_encoder.setHeaderData(header);
m_encoder.setTextData(slowData);
encoder.setHeaderData(header);
encoder.setTextData(slowData);
m_in = 0U;
buildAudio(words, encoder);
if (m_format != FORMAT_TEXT_TIME) {
std::string text = words.at(0U);
for (unsigned int i = 1U; i < words.size(); i++) {
text.push_back(' ');
text += words.at(i);
}
if (m_data.size() == 0U) {
CLog::logWarning(("Not sending, no audio files loaded"));
return false;
}
if(m_format == FORMAT_VOICE_TIME) {
std::string text = boost::algorithm::join(words, " ");
boost::replace_all(text, "_", " ");
CLog::logInfo(("Sending voice \"%s\", sending text \"%s\""), text.c_str(), slowData.c_str());
m_seqNo = 0U;
// Build the audio
lookup((" "));
lookup((" "));
lookup((" "));
lookup((" "));
for (unsigned int i = 0U; i < words.size(); i++)
lookup(words.at(i));
lookup((" "));
lookup((" "));
lookup((" "));
lookup((" "));
end();
} else {
CLog::logInfo(("Sending text \"%s\""), slowData.c_str());
for (unsigned int i = 0U; i < 21U; i++) {
CAMBEData* dataOut = new CAMBEData;
dataOut->setDestination(m_address, G2_DV_PORT);
dataOut->setSeq(i);
unsigned char buffer[DV_FRAME_LENGTH_BYTES];
::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES);
// Insert sync bytes when the sequence number is zero, slow data otherwise
if (i == 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_data[m_in] = dataOut;
m_in++;
}
CAMBEData* dataOut = new CAMBEData;
dataOut->setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES);
dataOut->setDestination(m_address, G2_DV_PORT);
dataOut->setSeq(0U);
dataOut->setEnd(true);
m_data[m_in] = dataOut;
m_in++;
CLog::logInfo("Sending voice \"%s\", sending text \"%s\"", text.c_str(), slowData.c_str());
}
if (m_in == 0U) {
CLog::logWarning(("Not sending, no audio files loaded"));
return false;
else {
CLog::logInfo("Sending text \"%s\"", slowData.c_str());
}
// Build id and socket lists
std::vector<unsigned int> ids;
std::vector<CUDPReaderWriter *> sockets;
for(auto rpt : m_repeaters) {
@ -1321,6 +1166,7 @@ bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int
ids.push_back(CHeaderData::createId());
}
// open them all
bool allOpen = std::all_of(sockets.begin(), sockets.end(), [](CUDPReaderWriter* s) { return s->open(); });
if(allOpen) {
//send headers
@ -1332,7 +1178,7 @@ bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int
Sleep(5);
}
// send audio
// send audio
bool loop = true;
unsigned int out = 0U;
auto start = std::chrono::high_resolution_clock::now();
@ -1353,7 +1199,7 @@ bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int
m_data[out] = nullptr;
out++;
if (m_in == out) {
if (out >= m_data.size()) {
loop = false;
break;
}
@ -1361,6 +1207,8 @@ bool CTimeServerThread::send(const std::vector<std::string> &words, unsigned int
}
}
m_data.clear();
for(auto socket : sockets) {
socket->close();
delete socket;

@ -27,37 +27,7 @@
#include "HeaderData.h"
#include "AMBEData.h"
#include "Thread.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"
class CTimeServerThread : public CThread
{
@ -72,23 +42,19 @@ public:
void kill();
private:
std::string m_callsign;
std::string m_callsign;
std::vector<std::string> m_repeaters;
std::string m_callsignG;
in_addr m_address;
std::string m_addressStr;
LANGUAGE m_language;
FORMAT m_format;
INTERVAL m_interval;
unsigned char* m_ambe;
unsigned int m_ambeLength;
std::unordered_map<std::string, CIndexRecord*> m_index;
unsigned int m_seqNo;
unsigned int m_in;
CSlowDataEncoder m_encoder;
CAMBEData** m_data;
bool m_killed;
std::string m_dataPath;
std::string m_callsignG;
in_addr m_address;
std::string m_addressStr;
LANGUAGE m_language;
FORMAT m_format;
INTERVAL m_interval;
CSlowDataEncoder m_encoder;
std::vector<CAMBEData*> m_data;
bool m_killed;
std::string m_dataPath;
CAMBEFileReader * m_ambeFileReader;
void sendTime(unsigned int hour, unsigned int min);
@ -110,9 +76,8 @@ private:
bool sendData(CUDPReaderWriter& socket, const CAMBEData& data);
bool loadAMBE();
bool readAMBE(const std::string& dir, const std::string& name);
bool readIndex(const std::string& dir, const std::string& name);
bool lookup(const std::string& id);
void end();
void buildAudio(const std::vector<std::string>& words, CSlowDataEncoder& slowDataEncoder);
};

Loading…
Cancel
Save

Powered by TurnKey Linux.