From 196908bedcefa19be8d89b1da69360ea32216c89 Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Mon, 1 May 2017 20:05:41 +0100 Subject: [PATCH] More work on audio prompts. --- Audio/de_DE.ambe | Bin 0 -> 3618 bytes Audio/de_DE.indx | 12 +++ Audio/en_GB.ambe | Bin 0 -> 4437 bytes Audio/en_GB.indx | 12 +++ Conf.cpp | 8 ++ Conf.h | 2 + DMRGateway.cpp | 6 +- DMRGateway.ini | 1 + Voice.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++- Voice.h | 30 +++++-- 10 files changed, 272 insertions(+), 13 deletions(-) create mode 100644 Audio/de_DE.ambe create mode 100644 Audio/de_DE.indx create mode 100644 Audio/en_GB.ambe create mode 100644 Audio/en_GB.indx diff --git a/Audio/de_DE.ambe b/Audio/de_DE.ambe new file mode 100644 index 0000000000000000000000000000000000000000..e4ec9f99bf7faecda868ff0b198c46114aa02118 GIT binary patch literal 3618 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 O)`SLDOeK&L*7tvi^n}*{ literal 0 HcmV?d00001 diff --git a/Audio/en_GB.indx b/Audio/en_GB.indx new file mode 100644 index 0000000..5d58500 --- /dev/null +++ b/Audio/en_GB.indx @@ -0,0 +1,12 @@ +0 0 50 +1 50 31 +2 81 30 +3 111 43 +4 154 42 +5 196 48 +6 244 40 +7 284 37 +8 321 32 +9 353 43 +connected 396 52 +disconnected 448 45 diff --git a/Conf.cpp b/Conf.cpp index 7a1846b..065573e 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -52,6 +52,7 @@ m_logFilePath(), m_logFileRoot(), m_voiceEnabled(true), m_voiceLanguage("en_GB"), +m_voiceDirectory(), m_dmrNetworkAddress(), m_dmrNetworkPort(0U), m_dmrNetworkLocal(0U), @@ -143,6 +144,8 @@ bool CConf::read() m_voiceEnabled = ::atoi(value) == 1; else if (::strcmp(key, "Language") == 0) m_voiceLanguage = value; + else if (::strcmp(key, "Directory") == 0) + m_voiceDirectory = value; } else if (section == SECTION_XLX_NETWORK) { if (::strcmp(key, "Address") == 0) m_xlxNetworkAddress = value; @@ -250,6 +253,11 @@ std::string CConf::getVoiceLanguage() const return m_voiceLanguage; } +std::string CConf::getVoiceDirectory() const +{ + return m_voiceDirectory; +} + std::string CConf::getXLXNetworkAddress() const { return m_xlxNetworkAddress; diff --git a/Conf.h b/Conf.h index 2a66c41..525dda3 100644 --- a/Conf.h +++ b/Conf.h @@ -50,6 +50,7 @@ public: // The Voice section bool getVoiceEnabled() const; std::string getVoiceLanguage() const; + std::string getVoiceDirectory() const; // The DMR Network section std::string getDMRNetworkAddress() const; @@ -80,6 +81,7 @@ private: bool m_voiceEnabled; std::string m_voiceLanguage; + std::string m_voiceDirectory; unsigned int m_logDisplayLevel; unsigned int m_logFileLevel; diff --git a/DMRGateway.cpp b/DMRGateway.cpp index 359dfde..f508203 100644 --- a/DMRGateway.cpp +++ b/DMRGateway.cpp @@ -250,13 +250,15 @@ int CDMRGateway::run() CVoice* voice = NULL; if (m_conf.getVoiceEnabled()) { - std::string language = m_conf.getVoiceLanguage(); + std::string language = m_conf.getVoiceLanguage(); + std::string directory = m_conf.getVoiceDirectory(); LogInfo("Voice Parameters"); LogInfo(" Enabled: yes"); LogInfo(" Language: %s", language.c_str()); + LogInfo(" Directory: %s", directory.c_str()); - voice = new CVoice(language, xlxSlot, xlxTG); + voice = new CVoice(directory, language, m_repeater->getId(), xlxSlot, xlxTG); bool ret = voice->open(); if (!ret) { diff --git a/DMRGateway.ini b/DMRGateway.ini index ddf5bb3..8bbf3d6 100644 --- a/DMRGateway.ini +++ b/DMRGateway.ini @@ -19,6 +19,7 @@ FileRoot=DMRGateway [Voice] Enabled=1 Language=en_GB +Directory=./Audio [XLX Network] Address=xlx950.epf.lu diff --git a/Voice.cpp b/Voice.cpp index 35bf22a..8cbebae 100644 --- a/Voice.cpp +++ b/Voice.cpp @@ -16,35 +16,190 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "DMRSlotType.h" +#include "DMRFullLC.h" +#include "DMREMB.h" #include "Voice.h" +#include "Sync.h" +#include "Log.h" -CVoice::CVoice(const std::string& language, unsigned int slot, unsigned int tg) : -m_language(language), +#include + +#include + +const unsigned char COLOR_CODE = 3U; + +CVoice::CVoice(const std::string& directory, const std::string& language, unsigned int id, unsigned int slot, unsigned int tg) : +m_indxFile(), +m_ambeFile(), m_slot(slot), -m_tg(tg), +m_lc(FLCO_GROUP, id, tg), +m_embeddedLC(), m_status(VS_NONE), m_timer(1000U, 1U), -m_stopWatch() +m_stopWatch(), +m_seqNo(0U), +m_streamId(0U), +m_sent(0U), +m_ambe(NULL), +m_data(), +m_it(), +m_start(), +m_length() { + m_embeddedLC.setLC(m_lc); + +#if defined(_WIN32) || defined(_WIN64) + m_indxFile = directory + "\\" + language + ".indx"; + m_ambeFile = directory + "\\" + language + ".ambe"; +#else + m_indxFile = directory + "/" + language + ".indx"; + m_ambeFile = directory + "/" + language + ".ambe"; +#endif } CVoice::~CVoice() { + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + + m_data.clear(); + + delete[] m_ambe; } bool CVoice::open() { + FILE* fpindx = ::fopen(m_indxFile.c_str(), "rt"); + if (fpindx == NULL) { + LogError("Unable to open the index file - %s", m_indxFile.c_str()); + return false; + } + + struct stat statStruct; + int ret = ::stat(m_ambeFile.c_str(), &statStruct); + if (ret != 0) { + LogError("Unable to stat the AMBE file - %s", m_ambeFile.c_str()); + ::fclose(fpindx); + return false; + } + + FILE* fpambe = ::fopen(m_ambeFile.c_str(), "rb"); + if (fpambe == NULL) { + LogError("Unable to open the AMBE file - %s", m_ambeFile.c_str()); + ::fclose(fpindx); + return false; + } + + m_ambe = new unsigned char[statStruct.st_size]; + + ::fread(m_ambe, 1U, statStruct.st_size, fpambe); + + char buffer[80U]; + while (::fgets(buffer, 80, fpindx) != NULL) { + char* p1 = ::strtok(buffer, "\t\r\n"); + char* p2 = ::strtok(NULL, "\t\r\n"); + char* p3 = ::strtok(NULL, "\t\r\n"); + + if (p1 != NULL && p2 != NULL && p3 != NULL) { + unsigned int start = ::atoi(p2) * 9U; + unsigned int length = ::atoi(p3) * 9U; + + m_start[p1] = start; + m_length[p1] = length; + } + } + + ::fclose(fpindx); + ::fclose(fpambe); + return true; } void CVoice::linkedTo(unsigned int id) { + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + + m_data.clear(); + + m_streamId = ::rand() + 1U; + m_seqNo = 0U; + + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + + unsigned int length = 0U; + unsigned char* ambe = new unsigned char[10000U]; + + + delete[] ambe; + + createHeaderTerminator(DT_TERMINATOR_WITH_LC); + m_status = VS_WAITING; m_timer.start(); } void CVoice::unlinked() { + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + + m_data.clear(); + + m_streamId = ::rand() + 1U; + m_seqNo = 0U; + + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + createHeaderTerminator(DT_VOICE_LC_HEADER); + + unsigned int start = m_start["disconnected"]; + unsigned int length = m_length["disconnected"] / 9U; + + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + + unsigned char* p = m_ambe + start; + for (unsigned int i = 0U; i < length; i++, p += 27U) { + CDMRData* data = new CDMRData; + + data->setSlotNo(m_slot); + data->setFLCO(FLCO_GROUP); + data->setSrcId(m_lc.getSrcId()); + data->setDstId(m_lc.getDstId()); + data->setN(); + data->setSeqNo(m_seqNo++); + data->setStreamId(m_streamId); + + ::memcpy(buffer + 0U, p + 0U, 9U); + ::memcpy(buffer + 9U, p + 9U, 9U); + ::memcpy(buffer + 15U, p + 9U, 9U); + ::memcpy(buffer + 24U, p + 18U, 9U); + + if (n == 0U) { + CSync::addDMRAudioSync(buffer); + data->setDataType(DT_VOICE_SYNC); + } else { + CDMREMB emb; + emb.setColorCode(COLOR_CODE); + emb.setPI(false); + emb.setLCSS(); + emb.getData(buffer); + + m_embeddedLC.getData(buffer, n); + + data->setDataType(DT_VOICE); + } + + data->setData(buffer); + + m_data.push_back(data); + } + + createHeaderTerminator(DT_TERMINATOR_WITH_LC); + m_status = VS_WAITING; m_timer.start(); } @@ -54,6 +209,25 @@ bool CVoice::read(CDMRData& data) if (m_status != VS_SENDING) return false; + unsigned int count = m_stopWatch.elapsed() / DMR_SLOT_TIME; + + if (m_sent < count) { + data = *(*m_it); + + ++m_sent; + ++m_it; + + if (m_it == m_data.end()) { + for (std::vector::iterator it = m_data.begin(); it != m_data.end(); ++it) + delete *it; + m_data.clear(); + m_timer.stop(); + m_status = VS_NONE; + } + + return true; + } + return false; } @@ -64,6 +238,38 @@ void CVoice::clock(unsigned int ms) if (m_status == VS_WAITING) { m_stopWatch.start(); m_status = VS_SENDING; + m_it = m_data.begin(); + m_sent = 0U; } } } + +void CVoice::createHeaderTerminator(unsigned char type) +{ + CDMRData* data = new CDMRData; + + data->setSlotNo(m_slot); + data->setFLCO(FLCO_GROUP); + data->setSrcId(m_lc.getSrcId()); + data->setDstId(m_lc.getDstId()); + data->setDataType(type); + data->setN(0U); + data->setSeqNo(m_seqNo++); + data->setStreamId(m_streamId); + + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + + CDMRFullLC fullLC; + fullLC.encode(m_lc, buffer, type); + + CDMRSlotType slotType; + slotType.setColorCode(COLOR_CODE); + slotType.setDataType(type); + slotType.getData(buffer); + + CSync::addDMRDataSync(buffer, true); + + data->setData(buffer); + + m_data.push_back(data); +} diff --git a/Voice.h b/Voice.h index cd63657..abda07b 100644 --- a/Voice.h +++ b/Voice.h @@ -19,11 +19,15 @@ #if !defined(Voice_H) #define Voice_H +#include "DMREmbeddedData.h" #include "StopWatch.h" #include "DMRData.h" +#include "DMRLC.h" #include "Timer.h" +#include #include +#include enum VOICE_STATUS { VS_NONE, @@ -33,7 +37,7 @@ enum VOICE_STATUS { class CVoice { public: - CVoice(const std::string& language, unsigned int slot, unsigned int tg); + CVoice(const std::string& directory, const std::string& language, unsigned int id, unsigned int slot, unsigned int tg); ~CVoice(); bool open(); @@ -46,12 +50,24 @@ public: void clock(unsigned int ms); private: - std::string m_language; - unsigned int m_slot; - unsigned int m_tg; - VOICE_STATUS m_status; - CTimer m_timer; - CStopWatch m_stopWatch; + std::string m_indxFile; + std::string m_ambeFile; + unsigned int m_slot; + CDMRLC m_lc; + CDMREmbeddedData m_embeddedLC; + VOICE_STATUS m_status; + CTimer m_timer; + CStopWatch m_stopWatch; + unsigned int m_seqNo; + unsigned int m_streamId; + unsigned int m_sent; + unsigned char* m_ambe; + std::vector m_data; + std::vector::const_iterator m_it; + std::unordered_map m_start; + std::unordered_map m_length; + + void createHeaderTerminator(unsigned char type); }; #endif