fix issue with UDP audio not sending metadata correctly; fix issue with enabling UDP audio; fix issue with incorrect address and port used for receiving remote UDP audio PCM data; fix issue with incorrect checking of destination and slot for DMR; fix issue with encodingDMRAudio frames and sending them too quickly; refactor how callEnd is handled;

pull/69/head
Bryan Biedenkapp 2 years ago
parent b281da766e
commit 1851cec087

@ -61,7 +61,7 @@ network:
# Enable PCM audio over UDP. # Enable PCM audio over UDP.
udpAudio: false udpAudio: false
# Enable meta data such as dstId and srcId in the UDP data # Enable meta data such as dstId and srcId in the UDP data
udpMetaData: false udpMetadata: false
# PCM over UDP send port. # PCM over UDP send port.
udpSendPort: 34001 udpSendPort: 34001
# PCM over UDP send address destination. # PCM over UDP send address destination.

@ -457,7 +457,7 @@ int HostBridge::run()
if (!Thread::runAsThread(this, threadNetworkProcess)) if (!Thread::runAsThread(this, threadNetworkProcess))
return EXIT_FAILURE; return EXIT_FAILURE;
if (!Thread::runAsThread(this, threadCallLockup)) if (!Thread::runAsThread(this, threadCallWatchdog))
return EXIT_FAILURE; return EXIT_FAILURE;
if (m_localAudio) { if (m_localAudio) {
@ -823,6 +823,9 @@ bool HostBridge::readParams()
m_localAudio = systemConf["localAudio"].as<bool>(true); m_localAudio = systemConf["localAudio"].as<bool>(true);
yaml::Node networkConf = m_conf["network"];
m_udpAudio = networkConf["udpAudio"].as<bool>(false);
LogInfo("General Parameters"); LogInfo("General Parameters");
LogInfo(" Rx Audio Gain: %.1f", m_rxAudioGain); LogInfo(" Rx Audio Gain: %.1f", m_rxAudioGain);
LogInfo(" Vocoder Decoder Audio Gain: %.1f", m_vocoderDecoderAudioGain); LogInfo(" Vocoder Decoder Audio Gain: %.1f", m_vocoderDecoderAudioGain);
@ -839,6 +842,7 @@ bool HostBridge::readParams()
LogInfo(" Dump Sample Levels: %s", m_dumpSampleLevel ? "yes" : "no"); LogInfo(" Dump Sample Levels: %s", m_dumpSampleLevel ? "yes" : "no");
LogInfo(" Grant Demands: %s", m_grantDemand ? "yes" : "no"); LogInfo(" Grant Demands: %s", m_grantDemand ? "yes" : "no");
LogInfo(" Local Audio: %s", m_localAudio ? "yes" : "no"); LogInfo(" Local Audio: %s", m_localAudio ? "yes" : "no");
LogInfo(" UDP Audio: %s", m_udpAudio ? "yes" : "no");
return true; return true;
} }
@ -969,7 +973,8 @@ bool HostBridge::createNetwork()
::LogSetNetwork(m_network); ::LogSetNetwork(m_network);
if (m_udpAudio) { if (m_udpAudio) {
m_udpAudioSocket = new Socket(m_udpSendAddress, m_udpSendPort); m_udpAudioSocket = new Socket(m_udpReceiveAddress, m_udpReceivePort);
m_udpAudioSocket->open();
} }
return true; return true;
@ -992,7 +997,6 @@ void HostBridge::processUDPAudio()
::memset(buffer, 0x00U, DATA_PACKET_LENGTH); ::memset(buffer, 0x00U, DATA_PACKET_LENGTH);
int length = m_udpAudioSocket->read(buffer, DATA_PACKET_LENGTH, addr, addrLen); int length = m_udpAudioSocket->read(buffer, DATA_PACKET_LENGTH, addr, addrLen);
if (length < 0) { if (length < 0) {
LogError(LOG_NET, "Failed reading data from the network");
return; return;
} }
@ -1012,7 +1016,7 @@ void HostBridge::processUDPAudio()
m_udpSrcId = m_srcId; m_udpSrcId = m_srcId;
if (m_udpMetadata) { if (m_udpMetadata) {
if (m_overrideSrcIdFromUDP) if (m_overrideSrcIdFromUDP)
m_udpSrcId = __GET_UINT32(buffer, pcmLength + 4U); m_udpSrcId = __GET_UINT32(buffer, pcmLength + 8U);
} }
m_udpDstId = m_dstId; m_udpDstId = m_dstId;
@ -1064,6 +1068,8 @@ void HostBridge::processUDPAudio()
// If audio detection is active and no call is in progress, encode and transmit the audio // If audio detection is active and no call is in progress, encode and transmit the audio
if (m_audioDetect && !m_callInProgress) { if (m_audioDetect && !m_callInProgress) {
m_dropTime.start();
switch (m_txMode) { switch (m_txMode) {
case TX_MODE_DMR: case TX_MODE_DMR:
encodeDMRAudioFrame(pcm, m_udpSrcId); encodeDMRAudioFrame(pcm, m_udpSrcId);
@ -1148,7 +1154,9 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length)
return; return;
// ensure destination ID matches and slot matches // ensure destination ID matches and slot matches
if (dstId != m_dstId && slotNo == m_slot) if (dstId != m_dstId)
return;
if (slotNo != m_slot)
return; return;
// is this a new call stream? // is this a new call stream?
@ -1320,8 +1328,8 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U); ::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
// embed destination and source IDs // embed destination and source IDs
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 0U)); __SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U)); __SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
} }
sockaddr_storage addr; sockaddr_storage addr;
@ -1395,6 +1403,8 @@ void HostBridge::encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
m_dmrSeqNo++; m_dmrSeqNo++;
delete[] data; delete[] data;
Thread::sleep(60U);
} }
// send DMR voice // send DMR voice
@ -1442,6 +1452,8 @@ void HostBridge::encodeDMRAudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
m_dmrSeqNo++; m_dmrSeqNo++;
::memset(m_ambeBuffer, 0x00U, 27U); ::memset(m_ambeBuffer, 0x00U, 27U);
m_ambeCount = 0U; m_ambeCount = 0U;
Thread::sleep(60U);
} }
int smpIdx = 0; int smpIdx = 0;
@ -1865,8 +1877,8 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U); ::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH * 2U);
// embed destination and source IDs // embed destination and source IDs
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 0U)); __SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U)); __SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
} }
sockaddr_storage addr; sockaddr_storage addr;
@ -2064,6 +2076,57 @@ void HostBridge::generatePreambleTone()
m_outputAudio.addData(sineSamples, frameCount); m_outputAudio.addData(sineSamples, frameCount);
} }
/* Helper to end a local or UDP call. */
void HostBridge::callEnd(uint32_t srcId, uint32_t dstId)
{
std::string trafficType = LOCAL_CALL;
if (m_trafficFromUDP) {
srcId = m_udpSrcId;
trafficType = UDP_CALL;
}
LogMessage(LOG_HOST, "%s, call end, srcId = %u, dstId = %u", trafficType.c_str(), srcId, dstId);
m_audioDetect = false;
m_dropTime.stop();
if (!m_callInProgress) {
switch (m_txMode) {
case TX_MODE_DMR:
{
dmr::data::NetData data = dmr::data::NetData();
data.setDataType(dmr::defines::DataType::TERMINATOR_WITH_LC);
data.setDstId(dstId);
data.setSrcId(srcId);
m_network->writeDMRTerminator(data, &m_dmrSeqNo, &m_dmrN, m_dmrEmbeddedData);
}
break;
case TX_MODE_P25:
{
p25::lc::LC lc = p25::lc::LC();
lc.setLCO(p25::defines::LCO::GROUP);
lc.setDstId(dstId);
lc.setSrcId(srcId);
p25::data::LowSpeedData lsd = p25::data::LowSpeedData();
uint8_t controlByte = 0x00U;
m_network->writeP25TDU(lc, lsd, controlByte);
}
break;
}
}
m_srcIdOverride = 0;
m_txStreamId = 0;
m_udpSrcId = 0;
m_udpDstId = 0;
m_trafficFromUDP = false;
}
/* Entry point to audio processing thread. */ /* Entry point to audio processing thread. */
void* HostBridge::threadAudioProcess(void* arg) void* HostBridge::threadAudioProcess(void* arg)
@ -2105,9 +2168,6 @@ void* HostBridge::threadAudioProcess(void* arg)
uint32_t ms = stopWatch.elapsed(); uint32_t ms = stopWatch.elapsed();
stopWatch.start(); stopWatch.start();
if (bridge->m_dropTime.isRunning())
bridge->m_dropTime.clock(ms);
// scope is intentional // scope is intentional
{ {
std::lock_guard<std::mutex> lock(m_audioMutex); std::lock_guard<std::mutex> lock(m_audioMutex);
@ -2182,45 +2242,7 @@ void* HostBridge::threadAudioProcess(void* arg)
// if we've exceeded the audio drop timeout, then really drop the audio // if we've exceeded the audio drop timeout, then really drop the audio
if (bridge->m_dropTime.isRunning() && bridge->m_dropTime.hasExpired()) { if (bridge->m_dropTime.isRunning() && bridge->m_dropTime.hasExpired()) {
if (bridge->m_audioDetect) { if (bridge->m_audioDetect) {
LogMessage(LOG_HOST, "%s, call end, srcId = %u, dstId = %u", trafficType.c_str(), srcId, dstId); bridge->callEnd(srcId, dstId);
bridge->m_audioDetect = false;
bridge->m_dropTime.stop();
if (!bridge->m_callInProgress) {
switch (bridge->m_txMode) {
case TX_MODE_DMR:
{
dmr::data::NetData data = dmr::data::NetData();
data.setDataType(dmr::defines::DataType::TERMINATOR_WITH_LC);
data.setDstId(dstId);
data.setSrcId(srcId);
bridge->m_network->writeDMRTerminator(data, &bridge->m_dmrSeqNo, &bridge->m_dmrN, bridge->m_dmrEmbeddedData);
}
break;
case TX_MODE_P25:
{
p25::lc::LC lc = p25::lc::LC();
lc.setLCO(p25::defines::LCO::GROUP);
lc.setDstId(dstId);
lc.setSrcId(srcId);
p25::data::LowSpeedData lsd = p25::data::LowSpeedData();
uint8_t controlByte = 0x00U;
bridge->m_network->writeP25TDU(lc, lsd, controlByte);
}
break;
}
}
bridge->m_srcIdOverride = 0;
bridge->m_txStreamId = 0;
bridge->m_udpSrcId = 0;
bridge->m_udpDstId = 0;
bridge->m_trafficFromUDP = false;
} }
} }
@ -2332,9 +2354,9 @@ void* HostBridge::threadNetworkProcess(void* arg)
return nullptr; return nullptr;
} }
/* Entry point to call lockup handler thread. */ /* Entry point to call watchdog handler thread. */
void* HostBridge::threadCallLockup(void* arg) void* HostBridge::threadCallWatchdog(void* arg)
{ {
thread_t* th = (thread_t*)arg; thread_t* th = (thread_t*)arg;
if (th != nullptr) { if (th != nullptr) {
@ -2344,7 +2366,7 @@ void* HostBridge::threadCallLockup(void* arg)
::pthread_detach(th->thread); ::pthread_detach(th->thread);
#endif // defined(_WIN32) #endif // defined(_WIN32)
std::string threadName("bridge:call-lockup"); std::string threadName("bridge:call-watchdog");
HostBridge* bridge = static_cast<HostBridge*>(th->obj); HostBridge* bridge = static_cast<HostBridge*>(th->obj);
if (bridge == nullptr) { if (bridge == nullptr) {
g_killed = true; g_killed = true;
@ -2373,6 +2395,9 @@ void* HostBridge::threadCallLockup(void* arg)
uint32_t ms = stopWatch.elapsed(); uint32_t ms = stopWatch.elapsed();
stopWatch.start(); stopWatch.start();
if (bridge->m_dropTime.isRunning())
bridge->m_dropTime.clock(ms);
std::string trafficType = LOCAL_CALL; std::string trafficType = LOCAL_CALL;
if (bridge->m_trafficFromUDP) if (bridge->m_trafficFromUDP)
trafficType = UDP_CALL; trafficType = UDP_CALL;
@ -2386,48 +2411,22 @@ void* HostBridge::threadCallLockup(void* arg)
ulong64_t temp = (bridge->m_dropTimeMS) * 1000U; ulong64_t temp = (bridge->m_dropTimeMS) * 1000U;
uint32_t dropTimeout = (uint32_t)((temp / 1000ULL + 1ULL) * 2U); uint32_t dropTimeout = (uint32_t)((temp / 1000ULL + 1ULL) * 2U);
// if we've exceeded the audio drop timeout, then really drop the audio if (bridge->m_trafficFromUDP) {
if ((bridge->m_dropTime.isRunning() && (bridge->m_dropTime.getTimer() >= dropTimeout)) || srcId = bridge->m_udpSrcId;
(!bridge->m_dropTime.isRunning() && !bridge->m_audioDetect && bridge->m_callInProgress)) { dstId = bridge->m_udpDstId;
LogMessage(LOG_HOST, "%s, call end (S)", trafficType.c_str());
bridge->m_audioDetect = false;
bridge->m_dropTime.stop();
if (!bridge->m_callInProgress) {
switch (bridge->m_txMode) {
case TX_MODE_DMR:
{
dmr::data::NetData data = dmr::data::NetData();
data.setDataType(dmr::defines::DataType::TERMINATOR_WITH_LC);
data.setDstId(dstId);
data.setSrcId(srcId);
bridge->m_network->writeDMRTerminator(data, &bridge->m_dmrSeqNo, &bridge->m_dmrN, bridge->m_dmrEmbeddedData); if (bridge->m_dropTime.isRunning() && bridge->m_dropTime.hasExpired()) {
} if (bridge->m_trafficFromUDP) {
break; bridge->callEnd(srcId, dstId);
case TX_MODE_P25:
{
p25::lc::LC lc = p25::lc::LC();
lc.setLCO(p25::defines::LCO::GROUP);
lc.setDstId(dstId);
lc.setSrcId(srcId);
p25::data::LowSpeedData lsd = p25::data::LowSpeedData();
uint8_t controlByte = 0x00U;
bridge->m_network->writeP25TDU(lc, lsd, controlByte);
}
break;
} }
} }
}
bridge->m_srcIdOverride = 0; else {
bridge->m_txStreamId = 0; // if we've exceeded the drop timeout, then really drop the audio
if (bridge->m_dropTime.isRunning() && (bridge->m_dropTime.getTimer() >= dropTimeout)) {
bridge->m_udpSrcId = 0; LogMessage(LOG_HOST, "%s, terminating stuck call", trafficType.c_str());
bridge->m_udpDstId = 0; bridge->callEnd(srcId, dstId);
bridge->m_trafficFromUDP = false; }
} }
Thread::sleep(5U); Thread::sleep(5U);

@ -411,6 +411,13 @@ private:
*/ */
void generatePreambleTone(); void generatePreambleTone();
/**
* @brief Helper to end a local or UDP call.
* @param srcId
* @param dstId
*/
void callEnd(uint32_t srcId, uint32_t dstId);
/** /**
* @brief Entry point to audio processing thread. * @brief Entry point to audio processing thread.
* @param arg Instance of the thread_t structure. * @param arg Instance of the thread_t structure.
@ -426,11 +433,11 @@ private:
static void* threadNetworkProcess(void* arg); static void* threadNetworkProcess(void* arg);
/** /**
* @brief Entry point to call lockup handler thread. * @brief Entry point to call watchdog handler thread.
* @param arg Instance of the thread_t structure. * @param arg Instance of the thread_t structure.
* @returns void* (Ignore) * @returns void* (Ignore)
*/ */
static void* threadCallLockup(void* arg); static void* threadCallWatchdog(void* arg);
}; };
#endif // __HOST_BRIDGE_H__ #endif // __HOST_BRIDGE_H__

Loading…
Cancel
Save

Powered by TurnKey Linux.