mirror of
https://github.com/g4klx/DMRGateway
synced 2025-12-20 21:25:37 +08:00
More work on audio prompts.
This commit is contained in:
BIN
Audio/de_DE.ambe
Normal file
BIN
Audio/de_DE.ambe
Normal file
Binary file not shown.
12
Audio/de_DE.indx
Normal file
12
Audio/de_DE.indx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
0 0 18
|
||||||
|
1 18 24
|
||||||
|
2 42 24
|
||||||
|
3 66 24
|
||||||
|
4 90 27
|
||||||
|
5 117 29
|
||||||
|
6 146 28
|
||||||
|
7 174 31
|
||||||
|
8 205 23
|
||||||
|
9 228 25
|
||||||
|
connected 253 77
|
||||||
|
disconnected 330 72
|
||||||
BIN
Audio/en_GB.ambe
Normal file
BIN
Audio/en_GB.ambe
Normal file
Binary file not shown.
12
Audio/en_GB.indx
Normal file
12
Audio/en_GB.indx
Normal file
@@ -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
|
||||||
8
Conf.cpp
8
Conf.cpp
@@ -52,6 +52,7 @@ m_logFilePath(),
|
|||||||
m_logFileRoot(),
|
m_logFileRoot(),
|
||||||
m_voiceEnabled(true),
|
m_voiceEnabled(true),
|
||||||
m_voiceLanguage("en_GB"),
|
m_voiceLanguage("en_GB"),
|
||||||
|
m_voiceDirectory(),
|
||||||
m_dmrNetworkAddress(),
|
m_dmrNetworkAddress(),
|
||||||
m_dmrNetworkPort(0U),
|
m_dmrNetworkPort(0U),
|
||||||
m_dmrNetworkLocal(0U),
|
m_dmrNetworkLocal(0U),
|
||||||
@@ -143,6 +144,8 @@ bool CConf::read()
|
|||||||
m_voiceEnabled = ::atoi(value) == 1;
|
m_voiceEnabled = ::atoi(value) == 1;
|
||||||
else if (::strcmp(key, "Language") == 0)
|
else if (::strcmp(key, "Language") == 0)
|
||||||
m_voiceLanguage = value;
|
m_voiceLanguage = value;
|
||||||
|
else if (::strcmp(key, "Directory") == 0)
|
||||||
|
m_voiceDirectory = value;
|
||||||
} else if (section == SECTION_XLX_NETWORK) {
|
} else if (section == SECTION_XLX_NETWORK) {
|
||||||
if (::strcmp(key, "Address") == 0)
|
if (::strcmp(key, "Address") == 0)
|
||||||
m_xlxNetworkAddress = value;
|
m_xlxNetworkAddress = value;
|
||||||
@@ -250,6 +253,11 @@ std::string CConf::getVoiceLanguage() const
|
|||||||
return m_voiceLanguage;
|
return m_voiceLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CConf::getVoiceDirectory() const
|
||||||
|
{
|
||||||
|
return m_voiceDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CConf::getXLXNetworkAddress() const
|
std::string CConf::getXLXNetworkAddress() const
|
||||||
{
|
{
|
||||||
return m_xlxNetworkAddress;
|
return m_xlxNetworkAddress;
|
||||||
|
|||||||
2
Conf.h
2
Conf.h
@@ -50,6 +50,7 @@ public:
|
|||||||
// The Voice section
|
// The Voice section
|
||||||
bool getVoiceEnabled() const;
|
bool getVoiceEnabled() const;
|
||||||
std::string getVoiceLanguage() const;
|
std::string getVoiceLanguage() const;
|
||||||
|
std::string getVoiceDirectory() const;
|
||||||
|
|
||||||
// The DMR Network section
|
// The DMR Network section
|
||||||
std::string getDMRNetworkAddress() const;
|
std::string getDMRNetworkAddress() const;
|
||||||
@@ -80,6 +81,7 @@ private:
|
|||||||
|
|
||||||
bool m_voiceEnabled;
|
bool m_voiceEnabled;
|
||||||
std::string m_voiceLanguage;
|
std::string m_voiceLanguage;
|
||||||
|
std::string m_voiceDirectory;
|
||||||
|
|
||||||
unsigned int m_logDisplayLevel;
|
unsigned int m_logDisplayLevel;
|
||||||
unsigned int m_logFileLevel;
|
unsigned int m_logFileLevel;
|
||||||
|
|||||||
@@ -250,13 +250,15 @@ int CDMRGateway::run()
|
|||||||
|
|
||||||
CVoice* voice = NULL;
|
CVoice* voice = NULL;
|
||||||
if (m_conf.getVoiceEnabled()) {
|
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("Voice Parameters");
|
||||||
LogInfo(" Enabled: yes");
|
LogInfo(" Enabled: yes");
|
||||||
LogInfo(" Language: %s", language.c_str());
|
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();
|
bool ret = voice->open();
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ FileRoot=DMRGateway
|
|||||||
[Voice]
|
[Voice]
|
||||||
Enabled=1
|
Enabled=1
|
||||||
Language=en_GB
|
Language=en_GB
|
||||||
|
Directory=./Audio
|
||||||
|
|
||||||
[XLX Network]
|
[XLX Network]
|
||||||
Address=xlx950.epf.lu
|
Address=xlx950.epf.lu
|
||||||
|
|||||||
214
Voice.cpp
214
Voice.cpp
@@ -16,35 +16,190 @@
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "DMRSlotType.h"
|
||||||
|
#include "DMRFullLC.h"
|
||||||
|
#include "DMREMB.h"
|
||||||
#include "Voice.h"
|
#include "Voice.h"
|
||||||
|
#include "Sync.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
CVoice::CVoice(const std::string& language, unsigned int slot, unsigned int tg) :
|
#include <cstring>
|
||||||
m_language(language),
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
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_slot(slot),
|
||||||
m_tg(tg),
|
m_lc(FLCO_GROUP, id, tg),
|
||||||
|
m_embeddedLC(),
|
||||||
m_status(VS_NONE),
|
m_status(VS_NONE),
|
||||||
m_timer(1000U, 1U),
|
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()
|
CVoice::~CVoice()
|
||||||
{
|
{
|
||||||
|
for (std::vector<CDMRData*>::iterator it = m_data.begin(); it != m_data.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
m_data.clear();
|
||||||
|
|
||||||
|
delete[] m_ambe;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVoice::open()
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVoice::linkedTo(unsigned int id)
|
void CVoice::linkedTo(unsigned int id)
|
||||||
{
|
{
|
||||||
|
for (std::vector<CDMRData*>::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_status = VS_WAITING;
|
||||||
m_timer.start();
|
m_timer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVoice::unlinked()
|
void CVoice::unlinked()
|
||||||
{
|
{
|
||||||
|
for (std::vector<CDMRData*>::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_status = VS_WAITING;
|
||||||
m_timer.start();
|
m_timer.start();
|
||||||
}
|
}
|
||||||
@@ -54,6 +209,25 @@ bool CVoice::read(CDMRData& data)
|
|||||||
if (m_status != VS_SENDING)
|
if (m_status != VS_SENDING)
|
||||||
return false;
|
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<CDMRData*>::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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +238,38 @@ void CVoice::clock(unsigned int ms)
|
|||||||
if (m_status == VS_WAITING) {
|
if (m_status == VS_WAITING) {
|
||||||
m_stopWatch.start();
|
m_stopWatch.start();
|
||||||
m_status = VS_SENDING;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
30
Voice.h
30
Voice.h
@@ -19,11 +19,15 @@
|
|||||||
#if !defined(Voice_H)
|
#if !defined(Voice_H)
|
||||||
#define Voice_H
|
#define Voice_H
|
||||||
|
|
||||||
|
#include "DMREmbeddedData.h"
|
||||||
#include "StopWatch.h"
|
#include "StopWatch.h"
|
||||||
#include "DMRData.h"
|
#include "DMRData.h"
|
||||||
|
#include "DMRLC.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
enum VOICE_STATUS {
|
enum VOICE_STATUS {
|
||||||
VS_NONE,
|
VS_NONE,
|
||||||
@@ -33,7 +37,7 @@ enum VOICE_STATUS {
|
|||||||
|
|
||||||
class CVoice {
|
class CVoice {
|
||||||
public:
|
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();
|
~CVoice();
|
||||||
|
|
||||||
bool open();
|
bool open();
|
||||||
@@ -46,12 +50,24 @@ public:
|
|||||||
void clock(unsigned int ms);
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_language;
|
std::string m_indxFile;
|
||||||
unsigned int m_slot;
|
std::string m_ambeFile;
|
||||||
unsigned int m_tg;
|
unsigned int m_slot;
|
||||||
VOICE_STATUS m_status;
|
CDMRLC m_lc;
|
||||||
CTimer m_timer;
|
CDMREmbeddedData m_embeddedLC;
|
||||||
CStopWatch m_stopWatch;
|
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<CDMRData*> m_data;
|
||||||
|
std::vector<CDMRData*>::const_iterator m_it;
|
||||||
|
std::unordered_map<std::string, unsigned int> m_start;
|
||||||
|
std::unordered_map<std::string, unsigned int> m_length;
|
||||||
|
|
||||||
|
void createHeaderTerminator(unsigned char type);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user