|
|
|
|
@ -4,7 +4,7 @@
|
|
|
|
|
* GPLv2 Open Source. Use is subject to license terms.
|
|
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2024 Bryan Biedenkapp, N2PLL
|
|
|
|
|
* Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#include "Defines.h"
|
|
|
|
|
@ -19,6 +19,7 @@
|
|
|
|
|
#include "common/p25/dfsi/LC.h"
|
|
|
|
|
#include "common/p25/lc/LC.h"
|
|
|
|
|
#include "common/p25/P25Utils.h"
|
|
|
|
|
#include "common/network/RTPHeader.h"
|
|
|
|
|
#include "common/network/udp/Socket.h"
|
|
|
|
|
#include "common/Log.h"
|
|
|
|
|
#include "common/StopWatch.h"
|
|
|
|
|
@ -30,6 +31,7 @@
|
|
|
|
|
#include "SampleTimeConversion.h"
|
|
|
|
|
|
|
|
|
|
using namespace network;
|
|
|
|
|
using namespace network::frame;
|
|
|
|
|
using namespace network::udp;
|
|
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
@ -67,6 +69,8 @@ static short seg_uend[8] = { 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FF
|
|
|
|
|
#define BIAS (0x84) // bias for linear code
|
|
|
|
|
#define CLIP 8159
|
|
|
|
|
|
|
|
|
|
const uint8_t RTP_G711_PAYLOAD_TYPE = 0x00U;
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Static Class Members
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
@ -161,17 +165,17 @@ static short search(short val, short* table, short size)
|
|
|
|
|
|
|
|
|
|
/* Helper to convert PCM into G.711 aLaw. */
|
|
|
|
|
|
|
|
|
|
uint8_t pcmToaLaw(short pcm)
|
|
|
|
|
uint8_t encodeALaw(short pcm)
|
|
|
|
|
{
|
|
|
|
|
short mask;
|
|
|
|
|
unsigned char aval;
|
|
|
|
|
uint8_t aval;
|
|
|
|
|
|
|
|
|
|
pcm = pcm >> 3;
|
|
|
|
|
|
|
|
|
|
if (pcm >= 0) {
|
|
|
|
|
mask = 0xD5; // sign (7th) bit = 1
|
|
|
|
|
mask = 0xD5U; // sign (7th) bit = 1
|
|
|
|
|
} else {
|
|
|
|
|
mask = 0x55; // sign bit = 0
|
|
|
|
|
mask = 0x55U; // sign bit = 0
|
|
|
|
|
pcm = -pcm - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -196,9 +200,9 @@ uint8_t pcmToaLaw(short pcm)
|
|
|
|
|
|
|
|
|
|
/* Helper to convert G.711 aLaw into PCM. */
|
|
|
|
|
|
|
|
|
|
short aLawToPCM(uint8_t alaw)
|
|
|
|
|
short decodeALaw(uint8_t alaw)
|
|
|
|
|
{
|
|
|
|
|
alaw ^= 0x55;
|
|
|
|
|
alaw ^= 0x55U;
|
|
|
|
|
|
|
|
|
|
short t = (alaw & QUANT_MASK) << 4;
|
|
|
|
|
short seg = ((unsigned)alaw & SEG_MASK) >> SEG_SHIFT;
|
|
|
|
|
@ -207,19 +211,19 @@ short aLawToPCM(uint8_t alaw)
|
|
|
|
|
t += 8;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
t += 0x108;
|
|
|
|
|
t += 0x108U;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
t += 0x108;
|
|
|
|
|
t += 0x108U;
|
|
|
|
|
t <<= seg - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ((alaw & SIGN_BIT) ? t : -t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to convert PCM into G.711 uLaw. */
|
|
|
|
|
/* Helper to convert PCM into G.711 MuLaw. */
|
|
|
|
|
|
|
|
|
|
uint8_t pcmTouLaw(short pcm)
|
|
|
|
|
uint8_t encodeMuLaw(short pcm)
|
|
|
|
|
{
|
|
|
|
|
short mask;
|
|
|
|
|
|
|
|
|
|
@ -252,9 +256,9 @@ uint8_t pcmTouLaw(short pcm)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to convert G.711 uLaw into PCM. */
|
|
|
|
|
/* Helper to convert G.711 MuLaw into PCM. */
|
|
|
|
|
|
|
|
|
|
short uLawToPCM(uint8_t ulaw)
|
|
|
|
|
short decodeMuLaw(uint8_t ulaw)
|
|
|
|
|
{
|
|
|
|
|
// complement to obtain normal u-law value
|
|
|
|
|
ulaw = ~ulaw;
|
|
|
|
|
@ -288,6 +292,7 @@ HostBridge::HostBridge(const std::string& confFile) :
|
|
|
|
|
m_udpReceiveAddress("127.0.0.1"),
|
|
|
|
|
m_udpNoIncludeLength(false),
|
|
|
|
|
m_udpUseULaw(false),
|
|
|
|
|
m_udpRTPFrames(false),
|
|
|
|
|
m_srcId(p25::defines::WUID_FNE),
|
|
|
|
|
m_srcIdOverride(0U),
|
|
|
|
|
m_overrideSrcIdFromMDC(false),
|
|
|
|
|
@ -345,7 +350,10 @@ HostBridge::HostBridge(const std::string& confFile) :
|
|
|
|
|
m_detectedSampleCnt(0U),
|
|
|
|
|
m_dumpSampleLevel(false),
|
|
|
|
|
m_running(false),
|
|
|
|
|
m_debug(false)
|
|
|
|
|
m_trace(false),
|
|
|
|
|
m_debug(false),
|
|
|
|
|
m_rtpSeqNo(0U),
|
|
|
|
|
m_rtpTimestamp(INVALID_TS)
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
,
|
|
|
|
|
m_encoderState(nullptr),
|
|
|
|
|
@ -962,6 +970,9 @@ bool HostBridge::readParams()
|
|
|
|
|
yaml::Node networkConf = m_conf["network"];
|
|
|
|
|
m_udpAudio = networkConf["udpAudio"].as<bool>(false);
|
|
|
|
|
|
|
|
|
|
m_trace = systemConf["trace"].as<bool>(false);
|
|
|
|
|
m_debug = systemConf["debug"].as<bool>(false);
|
|
|
|
|
|
|
|
|
|
LogInfo("General Parameters");
|
|
|
|
|
LogInfo(" Rx Audio Gain: %.1f", m_rxAudioGain);
|
|
|
|
|
LogInfo(" Vocoder Decoder Audio Gain: %.1f", m_vocoderDecoderAudioGain);
|
|
|
|
|
@ -980,6 +991,10 @@ bool HostBridge::readParams()
|
|
|
|
|
LogInfo(" Local Audio: %s", m_localAudio ? "yes" : "no");
|
|
|
|
|
LogInfo(" UDP Audio: %s", m_udpAudio ? "yes" : "no");
|
|
|
|
|
|
|
|
|
|
if (m_debug) {
|
|
|
|
|
LogInfo(" Debug: yes");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1005,8 +1020,12 @@ bool HostBridge::createNetwork()
|
|
|
|
|
m_udpReceiveAddress = networkConf["udpReceiveAddress"].as<std::string>();
|
|
|
|
|
m_udpUseULaw = networkConf["udpUseULaw"].as<bool>(false);
|
|
|
|
|
|
|
|
|
|
if (m_udpUseULaw)
|
|
|
|
|
if (m_udpUseULaw) {
|
|
|
|
|
m_udpNoIncludeLength = networkConf["udpNoIncludeLength"].as<bool>(false);
|
|
|
|
|
m_udpRTPFrames = networkConf["udpRTPFrames"].as<bool>(false);
|
|
|
|
|
if (m_udpRTPFrames)
|
|
|
|
|
m_udpNoIncludeLength = true; // RTP disables the length being included
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_udpUseULaw && m_udpMetadata)
|
|
|
|
|
m_udpMetadata = false; // metadata isn't supported when encoding uLaw
|
|
|
|
|
@ -1072,9 +1091,10 @@ bool HostBridge::createNetwork()
|
|
|
|
|
LogInfo(" UDP Audio Send Port: %u", m_udpSendPort);
|
|
|
|
|
LogInfo(" UDP Audio Receive Address: %s", m_udpReceiveAddress.c_str());
|
|
|
|
|
LogInfo(" UDP Audio Receive Port: %u", m_udpReceivePort);
|
|
|
|
|
LogInfo(" UDP Audio Use uLaw Encoding: %u", m_udpUseULaw ? "yes" : "no");
|
|
|
|
|
LogInfo(" UDP Audio Use uLaw Encoding: %s", m_udpUseULaw ? "yes" : "no");
|
|
|
|
|
if (m_udpUseULaw) {
|
|
|
|
|
LogInfo(" UDP Audio No Length Header: %u", m_udpNoIncludeLength ? "yes" : "no");
|
|
|
|
|
LogInfo(" UDP Audio No Length Header: %s", m_udpNoIncludeLength ? "yes" : "no");
|
|
|
|
|
LogInfo(" UDP Audio RTP Framed: %s", m_udpRTPFrames ? "yes" : "no");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1148,8 +1168,8 @@ void HostBridge::processUDPAudio()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (length > 0) {
|
|
|
|
|
if (m_debug)
|
|
|
|
|
Utils::dump(1U, "UDP Audio Network Packet", buffer, length);
|
|
|
|
|
if (m_trace)
|
|
|
|
|
Utils::dump(1U, "HostBridge()::processUDPAudio() Audio Network Packet", buffer, length);
|
|
|
|
|
|
|
|
|
|
uint32_t pcmLength = 0;
|
|
|
|
|
if (m_udpNoIncludeLength) {
|
|
|
|
|
@ -1158,14 +1178,30 @@ void HostBridge::processUDPAudio()
|
|
|
|
|
pcmLength = __GET_UINT32(buffer, 0U);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_udpRTPFrames)
|
|
|
|
|
pcmLength = MBE_SAMPLES_LENGTH * 2U;
|
|
|
|
|
|
|
|
|
|
UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmLength);
|
|
|
|
|
uint8_t* pcm = __pcm.get();
|
|
|
|
|
|
|
|
|
|
if (m_udpNoIncludeLength) {
|
|
|
|
|
::memcpy(pcm, buffer, pcmLength);
|
|
|
|
|
if (m_udpRTPFrames) {
|
|
|
|
|
RTPHeader rtpHeader = RTPHeader();
|
|
|
|
|
rtpHeader.decode(buffer);
|
|
|
|
|
|
|
|
|
|
if (rtpHeader.getPayloadType() != RTP_G711_PAYLOAD_TYPE) {
|
|
|
|
|
LogError(LOG_HOST, "Invalid RTP payload type %u", rtpHeader.getPayloadType());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::memcpy(pcm, buffer + RTP_HEADER_LENGTH_BYTES, MBE_SAMPLES_LENGTH * 2U);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
::memcpy(pcm, buffer + 4U, pcmLength);
|
|
|
|
|
if (m_udpNoIncludeLength) {
|
|
|
|
|
::memcpy(pcm, buffer, pcmLength);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
::memcpy(pcm, buffer + 4U, pcmLength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Utils::dump(1U, "PCM RECV BYTE BUFFER", pcm, pcmLength);
|
|
|
|
|
@ -1183,10 +1219,20 @@ void HostBridge::processUDPAudio()
|
|
|
|
|
int smpIdx = 0;
|
|
|
|
|
short samples[MBE_SAMPLES_LENGTH];
|
|
|
|
|
if (m_udpUseULaw) {
|
|
|
|
|
for (uint32_t pcmIdx = 0; pcmIdx < pcmLength; pcmIdx++) {
|
|
|
|
|
samples[smpIdx] = uLawToPCM(pcm[pcmIdx]);
|
|
|
|
|
if (m_trace)
|
|
|
|
|
Utils::dump(1U, "HostBridge()::processUDPAudio() uLaw Audio", pcm, MBE_SAMPLES_LENGTH * 2U);
|
|
|
|
|
|
|
|
|
|
for (uint32_t pcmIdx = 0; pcmIdx < MBE_SAMPLES_LENGTH; pcmIdx++) {
|
|
|
|
|
samples[smpIdx] = decodeMuLaw(pcm[pcmIdx]);
|
|
|
|
|
smpIdx++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int pcmIdx = 0;
|
|
|
|
|
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
|
|
|
|
|
pcm[pcmIdx + 0] = (uint8_t)(samples[smpIdx] & 0xFF);
|
|
|
|
|
pcm[pcmIdx + 1] = (uint8_t)((samples[smpIdx] >> 8) & 0xFF);
|
|
|
|
|
pcmIdx += 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (uint32_t pcmIdx = 0; pcmIdx < pcmLength; pcmIdx += 2) {
|
|
|
|
|
@ -1379,6 +1425,9 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length)
|
|
|
|
|
m_rxDMRPILC = lc::PrivacyLC();
|
|
|
|
|
m_rxStartTime = 0U;
|
|
|
|
|
m_rxStreamId = 0U;
|
|
|
|
|
|
|
|
|
|
m_rtpSeqNo = 0U;
|
|
|
|
|
m_rtpTimestamp = INVALID_TS;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1474,8 +1523,11 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
|
|
|
|
|
uint8_t pcm[MBE_SAMPLES_LENGTH * 2U];
|
|
|
|
|
if (m_udpUseULaw) {
|
|
|
|
|
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
|
|
|
|
|
pcm[smpIdx] = pcmTouLaw(samples[smpIdx]);
|
|
|
|
|
pcm[smpIdx] = encodeMuLaw(samples[smpIdx]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_trace)
|
|
|
|
|
Utils::dump(1U, "HostBridge()::decodeDMRAudioFrame() Encoded uLaw Audio", pcm, MBE_SAMPLES_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
|
|
|
|
|
@ -1498,6 +1550,22 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
|
|
|
|
|
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
|
|
|
|
|
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// are we sending RTP audio frames?
|
|
|
|
|
if (m_udpRTPFrames) {
|
|
|
|
|
uint8_t* rtpFrame = generateRTPHeaders(MBE_SAMPLES_LENGTH, m_rtpSeqNo);
|
|
|
|
|
if (rtpFrame != nullptr) {
|
|
|
|
|
length += RTP_HEADER_LENGTH_BYTES;
|
|
|
|
|
uint8_t* newAudioData = new uint8_t[length];
|
|
|
|
|
::memcpy(newAudioData, rtpFrame, RTP_HEADER_LENGTH_BYTES);
|
|
|
|
|
::memcpy(newAudioData + RTP_HEADER_LENGTH_BYTES, audioData, MBE_SAMPLES_LENGTH);
|
|
|
|
|
delete[] audioData;
|
|
|
|
|
|
|
|
|
|
audioData = newAudioData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_rtpSeqNo++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
|
|
|
|
|
@ -1583,6 +1651,9 @@ void HostBridge::encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
|
|
|
|
|
|
|
|
|
|
dmrData.setData(data);
|
|
|
|
|
|
|
|
|
|
LogMessage(LOG_HOST, DMR_DT_VOICE_LC_HEADER ", slot = %u, srcId = %u, dstId = %u, FLCO = $%02X", m_slot,
|
|
|
|
|
dmrLC.getSrcId(), dmrLC.getDstId(), dmrData.getFLCO());
|
|
|
|
|
|
|
|
|
|
m_network->writeDMR(dmrData, false);
|
|
|
|
|
m_txStreamId = m_network->getDMRStreamId(m_slot);
|
|
|
|
|
|
|
|
|
|
@ -1798,6 +1869,9 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
|
|
|
|
|
m_rxP25LC = lc::LC();
|
|
|
|
|
m_rxStartTime = 0U;
|
|
|
|
|
m_rxStreamId = 0U;
|
|
|
|
|
|
|
|
|
|
m_rtpSeqNo = 0U;
|
|
|
|
|
m_rtpTimestamp = INVALID_TS;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2040,8 +2114,11 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
|
|
|
|
|
uint8_t pcm[MBE_SAMPLES_LENGTH * 2U];
|
|
|
|
|
if (m_udpUseULaw) {
|
|
|
|
|
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
|
|
|
|
|
pcm[smpIdx] = pcmTouLaw(samples[smpIdx]);
|
|
|
|
|
pcm[smpIdx] = encodeMuLaw(samples[smpIdx]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_trace)
|
|
|
|
|
Utils::dump(1U, "HostBridge()::decodeP25AudioFrame() Encoded uLaw Audio", pcm, MBE_SAMPLES_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (uint32_t smpIdx = 0; smpIdx < MBE_SAMPLES_LENGTH; smpIdx++) {
|
|
|
|
|
@ -2064,6 +2141,22 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
|
|
|
|
|
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
|
|
|
|
|
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// are we sending RTP audio frames?
|
|
|
|
|
if (m_udpRTPFrames) {
|
|
|
|
|
uint8_t* rtpFrame = generateRTPHeaders(MBE_SAMPLES_LENGTH, m_rtpSeqNo);
|
|
|
|
|
if (rtpFrame != nullptr) {
|
|
|
|
|
length += RTP_HEADER_LENGTH_BYTES;
|
|
|
|
|
uint8_t* newAudioData = new uint8_t[length];
|
|
|
|
|
::memcpy(newAudioData, rtpFrame, RTP_HEADER_LENGTH_BYTES);
|
|
|
|
|
::memcpy(newAudioData + RTP_HEADER_LENGTH_BYTES, audioData, MBE_SAMPLES_LENGTH);
|
|
|
|
|
delete[] audioData;
|
|
|
|
|
|
|
|
|
|
audioData = newAudioData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_rtpSeqNo++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
__SET_UINT32((MBE_SAMPLES_LENGTH * 2U), audioData, 0U);
|
|
|
|
|
@ -2248,7 +2341,7 @@ void HostBridge::encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
|
|
|
|
|
m_p25N++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to generate the preamble tone. */
|
|
|
|
|
/* Helper to generate the single-tone preamble tone. */
|
|
|
|
|
|
|
|
|
|
void HostBridge::generatePreambleTone()
|
|
|
|
|
{
|
|
|
|
|
@ -2260,6 +2353,8 @@ void HostBridge::generatePreambleTone()
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ma_waveform_set_frequency(&m_maSineWaveform, m_preambleTone);
|
|
|
|
|
|
|
|
|
|
ma_uint32 pcmBytes = frameCount * ma_get_bytes_per_frame(m_maDevice.capture.format, m_maDevice.capture.channels);
|
|
|
|
|
UInt8Array __sine = std::make_unique<uint8_t[]>(pcmBytes);
|
|
|
|
|
uint8_t* sine = __sine.get();
|
|
|
|
|
@ -2278,6 +2373,40 @@ void HostBridge::generatePreambleTone()
|
|
|
|
|
m_outputAudio.addData(sineSamples, frameCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to generate outgoing RTP headers. */
|
|
|
|
|
|
|
|
|
|
uint8_t* HostBridge::generateRTPHeaders(uint8_t msgLen, uint16_t& rtpSeq)
|
|
|
|
|
{
|
|
|
|
|
uint32_t timestamp = m_rtpTimestamp;
|
|
|
|
|
if (timestamp != INVALID_TS) {
|
|
|
|
|
timestamp += (RTP_GENERIC_CLOCK_RATE / 50);
|
|
|
|
|
if (m_debug)
|
|
|
|
|
LogDebug(LOG_NET, "HostBridge::generateRTPHeaders() RTP, previous TS = %u, TS = %u, rtpSeq = %u", m_rtpTimestamp, timestamp, rtpSeq);
|
|
|
|
|
m_rtpTimestamp = timestamp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate RTP header
|
|
|
|
|
RTPHeader header = RTPHeader();
|
|
|
|
|
|
|
|
|
|
header.setPayloadType(RTP_G711_PAYLOAD_TYPE);
|
|
|
|
|
header.setTimestamp(timestamp);
|
|
|
|
|
header.setSequence(rtpSeq);
|
|
|
|
|
header.setSSRC(m_network->getPeerId());
|
|
|
|
|
|
|
|
|
|
uint8_t* buffer = new uint8_t[RTP_HEADER_LENGTH_BYTES + msgLen];
|
|
|
|
|
::memset(buffer, 0x00U, RTP_HEADER_LENGTH_BYTES + msgLen);
|
|
|
|
|
|
|
|
|
|
header.encode(buffer);
|
|
|
|
|
|
|
|
|
|
if (timestamp == INVALID_TS) {
|
|
|
|
|
if (m_debug)
|
|
|
|
|
LogDebug(LOG_NET, "HostBridge::generateRTPHeaders() RTP, initial TS = %u, rtpSeq = %u", header.getTimestamp(), rtpSeq);
|
|
|
|
|
m_rtpTimestamp = header.getTimestamp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper to end a local or UDP call. */
|
|
|
|
|
|
|
|
|
|
void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
|
|
|
|
|
@ -2297,10 +2426,25 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
|
|
|
|
|
switch (m_txMode) {
|
|
|
|
|
case TX_MODE_DMR:
|
|
|
|
|
{
|
|
|
|
|
dmr::defines::DataType::E dataType = dmr::defines::DataType::VOICE_SYNC;
|
|
|
|
|
if (m_dmrN == 0)
|
|
|
|
|
dataType = dmr::defines::DataType::VOICE_SYNC;
|
|
|
|
|
else {
|
|
|
|
|
dataType = dmr::defines::DataType::VOICE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dmr::data::NetData data = dmr::data::NetData();
|
|
|
|
|
data.setDataType(dmr::defines::DataType::TERMINATOR_WITH_LC);
|
|
|
|
|
data.setDstId(dstId);
|
|
|
|
|
data.setSlotNo(m_slot);
|
|
|
|
|
data.setDataType(dataType);
|
|
|
|
|
data.setSrcId(srcId);
|
|
|
|
|
data.setDstId(dstId);
|
|
|
|
|
data.setFLCO(dmr::defines::FLCO::GROUP);
|
|
|
|
|
data.setN(m_dmrN);
|
|
|
|
|
data.setSeqNo(m_dmrSeqNo);
|
|
|
|
|
data.setBER(0U);
|
|
|
|
|
data.setRSSI(0U);
|
|
|
|
|
|
|
|
|
|
LogMessage(LOG_HOST, DMR_DT_TERMINATOR_WITH_LC ", slot = %u, dstId = %u", m_slot, dstId);
|
|
|
|
|
|
|
|
|
|
m_network->writeDMRTerminator(data, &m_dmrSeqNo, &m_dmrN, m_dmrEmbeddedData);
|
|
|
|
|
m_network->resetDMR(data.getSlotNo());
|
|
|
|
|
@ -2315,6 +2459,8 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
|
|
|
|
|
|
|
|
|
|
p25::data::LowSpeedData lsd = p25::data::LowSpeedData();
|
|
|
|
|
|
|
|
|
|
LogMessage(LOG_HOST, P25_TDU_STR);
|
|
|
|
|
|
|
|
|
|
uint8_t controlByte = 0x00U;
|
|
|
|
|
m_network->writeP25TDU(lc, lsd, controlByte);
|
|
|
|
|
m_network->resetP25();
|
|
|
|
|
@ -2334,6 +2480,9 @@ void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
|
|
|
|
|
m_dmrN = 0U;
|
|
|
|
|
m_p25SeqNo = 0U;
|
|
|
|
|
m_p25N = 0U;
|
|
|
|
|
|
|
|
|
|
m_rtpSeqNo = 0U;
|
|
|
|
|
m_rtpTimestamp = INVALID_TS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Entry point to audio processing thread. */
|
|
|
|
|
|