implement support for a silence threshold in DMR (this will help null highly degraded audio to prevent horrifying ear destroying screeching); some minor code cleanup (mostly removing magic numbers!);

pull/12/head
Bryan Biedenkapp 4 years ago
parent d778367583
commit 43f8f6e8ae

@ -41,6 +41,7 @@ protocols:
dumpCsbkData: false dumpCsbkData: false
callHang: 5 callHang: 5
txHang: 8 txHang: 8
silenceThreshold: 21
queueSize: 5000 queueSize: 5000
verbose: true verbose: true
debug: false debug: false
@ -92,7 +93,7 @@ system:
dmrNetId: 1 dmrNetId: 1
voiceChNo: voiceChNo:
- 1 - 1
colorCode: 5 colorCode: 1
nac: 293 nac: 293
pSuperGroup: FFFF pSuperGroup: FFFF
netId: BB800 netId: BB800

@ -136,12 +136,22 @@ void Control::setOptions(yaml::Node& conf, uint32_t netId, uint8_t siteId, uint8
m_slot2->setTSCC(enableTSCC, dedicatedTSCC); m_slot2->setTSCC(enableTSCC, dedicatedTSCC);
break; break;
default: default:
LogError(LOG_NET, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo); LogError(LOG_DMR, "DMR, invalid slot, TSCC disabled, slotNo = %u", m_tsccSlotNo);
break; break;
} }
uint32_t silenceThreshold = dmrProtocol["silenceThreshold"].as<uint32_t>(dmr::DEFAULT_SILENCE_THRESHOLD);
if (silenceThreshold > MAX_DMR_VOICE_ERRORS) {
LogWarning(LOG_DMR, "Silence threshold > %u, defaulting to %u", dmr::MAX_DMR_VOICE_ERRORS, dmr::DEFAULT_SILENCE_THRESHOLD);
silenceThreshold = dmr::DEFAULT_SILENCE_THRESHOLD;
}
m_slot1->setSilenceThreshold(silenceThreshold);
m_slot2->setSilenceThreshold(silenceThreshold);
if (printOptions) { if (printOptions) {
LogInfo(" TSCC Slot: %u", m_tsccSlotNo); LogInfo(" TSCC Slot: %u", m_tsccSlotNo);
LogInfo(" Silence Threshold: %u (%.1f%%)", silenceThreshold, float(silenceThreshold) / 1.41F);
} }
} }

@ -99,6 +99,8 @@ namespace dmr
0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U, 0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U,
0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU }; 0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU };
const uint8_t DMR_NULL_AMBE[] = { 0xB1U, 0xA8U, 0x22U, 0x25U, 0x6BU, 0xD1U, 0x6CU, 0xCFU, 0x67U };
const uint8_t PAYLOAD_LEFT_MASK[] = { 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U }; const uint8_t PAYLOAD_LEFT_MASK[] = { 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U };
const uint8_t PAYLOAD_RIGHT_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU }; const uint8_t PAYLOAD_RIGHT_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU };
@ -130,6 +132,9 @@ namespace dmr
const uint16_t DMR_LOGICAL_CH_ABSOLUTE = 0xFFFU; const uint16_t DMR_LOGICAL_CH_ABSOLUTE = 0xFFFU;
const uint32_t DEFAULT_SILENCE_THRESHOLD = 21U;
const uint32_t MAX_DMR_VOICE_ERRORS = 141U;
// PDU Data Formats // PDU Data Formats
const uint8_t DPF_UDT = 0x00U; const uint8_t DPF_UDT = 0x00U;
const uint8_t DPF_RESPONSE = 0x01U; const uint8_t DPF_RESPONSE = 0x01U;

@ -142,6 +142,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz
m_minRSSI(0U), m_minRSSI(0U),
m_aveRSSI(0U), m_aveRSSI(0U),
m_rssiCount(0U), m_rssiCount(0U),
m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD),
m_ccSeq(0U), m_ccSeq(0U),
m_ccRunning(false), m_ccRunning(false),
m_enableTSCC(false), m_enableTSCC(false),
@ -525,6 +526,15 @@ void Slot::setTSCC(bool enable, bool dedicated)
m_dedicatedTSCC = dedicated; m_dedicatedTSCC = dedicated;
} }
/// <summary>
/// Helper to set the voice error silence threshold.
/// </summary>
/// <param name="threshold"></param>
void Slot::setSilenceThreshold(uint32_t threshold)
{
m_silenceThreshold = threshold;
}
/// <summary> /// <summary>
/// Helper to initialize the DMR slot processor. /// Helper to initialize the DMR slot processor.
/// </summary> /// </summary>

@ -93,6 +93,8 @@ namespace dmr
/// <summary>Helper to enable and configure TSCC support for this slot.</summary> /// <summary>Helper to enable and configure TSCC support for this slot.</summary>
void setTSCC(bool enable, bool dedicated); void setTSCC(bool enable, bool dedicated);
/// <summary>Helper to set the voice error silence threshold.</summary>
void setSilenceThreshold(uint32_t threshold);
/// <summary>Helper to initialize the slot processor.</summary> /// <summary>Helper to initialize the slot processor.</summary>
static void init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem, static void init(uint32_t colorCode, SiteData siteData, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem,
@ -156,6 +158,8 @@ namespace dmr
uint32_t m_aveRSSI; uint32_t m_aveRSSI;
uint32_t m_rssiCount; uint32_t m_rssiCount;
uint32_t m_silenceThreshold;
uint8_t m_ccSeq; uint8_t m_ccSeq;
bool m_ccRunning; bool m_ccRunning;

@ -259,6 +259,13 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
errors, float(errors) / 1.41F); errors, float(errors) / 1.41F);
} }
if (errors > m_slot->m_silenceThreshold) {
insertNullAudio(data + 2U);
m_fec.regenerateDMR(data + 2U);
LogWarning(LOG_RF, DMR_DT_VOICE_SYNC ", exceeded lost audio threshold, filling in");
}
m_slot->m_rfErrs += errors; m_slot->m_rfErrs += errors;
} }
@ -312,6 +319,20 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
m_rfN, errors, float(errors) / 1.41F); m_rfN, errors, float(errors) / 1.41F);
} }
if (errors > m_slot->m_silenceThreshold) {
// Get the LCSS from the EMB
data::EMB emb;
emb.decode(data + 2U);
insertNullAudio(data + 2U);
m_fec.regenerateDMR(data + 2U);
// Regenerate EMB
emb.encode(data + 2U);
LogWarning(LOG_RF, DMR_DT_VOICE ", exceeded lost audio threshold, filling in");
}
m_slot->m_rfErrs += errors; m_slot->m_rfErrs += errors;
} }
@ -540,10 +561,24 @@ bool VoicePacket::process(uint8_t* data, uint32_t len)
if (fid == FID_ETSI || fid == FID_DMRA) { if (fid == FID_ETSI || fid == FID_DMRA) {
errors = m_fec.regenerateDMR(data + 2U); errors = m_fec.regenerateDMR(data + 2U);
if (m_verbose) { if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DT_VOICE audio, sequence no = %u, errs = %u/141 (%.1f%%)", LogMessage(LOG_RF, DMR_DT_VOICE ", audio, slot = %u, sequence no = %u, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, m_rfN, errors, float(errors) / 1.41F); m_slot->m_slotNo, m_rfN, errors, float(errors) / 1.41F);
} }
if (errors > m_slot->m_silenceThreshold) {
// Get the LCSS from the EMB
data::EMB emb;
emb.decode(data + 2U);
insertNullAudio(data + 2U);
m_fec.regenerateDMR(data + 2U);
// Regenerate EMB
emb.encode(data + 2U);
LogWarning(LOG_RF, DMR_DT_VOICE ", exceeded lost audio threshold, filling in");
}
m_slot->m_rfErrs += errors; m_slot->m_rfErrs += errors;
} }
@ -1121,6 +1156,27 @@ void VoicePacket::logGPSPosition(const uint32_t srcId, const uint8_t* data)
LogMessage(LOG_DMR, "GPS position for %u [lat %f, long %f] (Position error %s)", srcId, latitude, longitude, error); LogMessage(LOG_DMR, "GPS position for %u [lat %f, long %f] (Position error %s)", srcId, latitude, longitude, error);
} }
/// <summary>
/// Helper to insert AMBE null frames for missing audio.
/// </summary>
/// <param name="data"></param>
void VoicePacket::insertNullAudio(uint8_t* data)
{
uint8_t* ambeBuffer = new uint8_t[dmr::DMR_AMBE_LENGTH_BYTES];
::memset(ambeBuffer, 0x00U, dmr::DMR_AMBE_LENGTH_BYTES);
for (uint32_t i = 0; i < 3U; i++) {
::memcpy(ambeBuffer + (i * 9U), DMR_NULL_AMBE, 9U);
}
::memcpy(data, ambeBuffer, 13U);
data[13U] = ambeBuffer[13U] & 0xF0U;
data[19U] = ambeBuffer[13U] & 0x0FU;
::memcpy(data + 20U, ambeBuffer + 14U, 13U);
delete[] ambeBuffer;
}
/// <summary> /// <summary>
/// Helper to insert DMR AMBE silence frames. /// Helper to insert DMR AMBE silence frames.
/// </summary> /// </summary>

@ -105,6 +105,8 @@ namespace dmr
/// <summary></summary> /// <summary></summary>
void logGPSPosition(const uint32_t srcId, const uint8_t* data); void logGPSPosition(const uint32_t srcId, const uint8_t* data);
/// <summary>Helper to insert AMBE null frames for missing audio.</summary>
void insertNullAudio(uint8_t* data);
/// <summary>Helper to insert DMR AMBE silence frames.</summary> /// <summary>Helper to insert DMR AMBE silence frames.</summary>
bool insertSilence(const uint8_t* data, uint8_t seqNo); bool insertSilence(const uint8_t* data, uint8_t seqNo);
/// <summary>Helper to insert DMR AMBE silence frames.</summary> /// <summary>Helper to insert DMR AMBE silence frames.</summary>

@ -214,6 +214,10 @@ void Control::setOptions(yaml::Node& conf, const std::string cwCallsign, const s
m_ackTSBKRequests = control["ackRequests"].as<bool>(true); m_ackTSBKRequests = control["ackRequests"].as<bool>(true);
m_voice->m_silenceThreshold = p25Protocol["silenceThreshold"].as<uint32_t>(p25::DEFAULT_SILENCE_THRESHOLD); m_voice->m_silenceThreshold = p25Protocol["silenceThreshold"].as<uint32_t>(p25::DEFAULT_SILENCE_THRESHOLD);
if (m_voice->m_silenceThreshold > MAX_P25_VOICE_ERRORS) {
LogWarning(LOG_P25, "Silence threshold > %u, defaulting to %u", p25::MAX_P25_VOICE_ERRORS, p25::DEFAULT_SILENCE_THRESHOLD);
m_voice->m_silenceThreshold = p25::DEFAULT_SILENCE_THRESHOLD;
}
m_disableNetworkHDU = p25Protocol["disableNetworkHDU"].as<bool>(false); m_disableNetworkHDU = p25Protocol["disableNetworkHDU"].as<bool>(false);

@ -202,6 +202,7 @@ namespace p25
const uint32_t P25_TGID_ALL = 0xFFFFU; const uint32_t P25_TGID_ALL = 0xFFFFU;
const uint32_t DEFAULT_SILENCE_THRESHOLD = 124U; const uint32_t DEFAULT_SILENCE_THRESHOLD = 124U;
const uint32_t MAX_P25_VOICE_ERRORS = 1233U;
// PDU Format Type(s) // PDU Format Type(s)
const uint8_t PDU_FMT_RSP = 0x03U; const uint8_t PDU_FMT_RSP = 0x03U;

@ -889,7 +889,7 @@ VoicePacket::VoicePacket(Control* p25, network::BaseNetwork* network, bool debug
m_hadVoice(false), m_hadVoice(false),
m_lastRejectId(0U), m_lastRejectId(0U),
m_lastPatchGroup(0U), m_lastPatchGroup(0U),
m_silenceThreshold(124U), m_silenceThreshold(DEFAULT_SILENCE_THRESHOLD),
m_vocLDU1Count(0U), m_vocLDU1Count(0U),
m_verbose(verbose), m_verbose(verbose),
m_debug(debug) m_debug(debug)

Loading…
Cancel
Save

Powered by TurnKey Linux.