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_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;
|
||||
|
||||
2
Conf.h
2
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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -19,6 +19,7 @@ FileRoot=DMRGateway
|
||||
[Voice]
|
||||
Enabled=1
|
||||
Language=en_GB
|
||||
Directory=./Audio
|
||||
|
||||
[XLX Network]
|
||||
Address=xlx950.epf.lu
|
||||
|
||||
214
Voice.cpp
214
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 <cstring>
|
||||
|
||||
#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_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<CDMRData*>::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<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_timer.start();
|
||||
}
|
||||
|
||||
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_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<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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
30
Voice.h
30
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 <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<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
|
||||
|
||||
Reference in New Issue
Block a user