Add support for USRP (#83)

* Add support for USRP UDP transport

* Maintain USRP sequence

* Oops not sure how I did that

* Update DMR to be like P25

* Check for invalid UDP configuration

---------

Co-authored-by: firealarmss <caleb.k4php@gmail.com>
4.11f_maint
firealarmss 11 months ago committed by GitHub
parent db1d000b21
commit aedabceac7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -76,6 +76,8 @@ network:
# Flag indicating UDP audio should be RTP framed.
# NOTE: This flag is only applicable when encoding G.711 uLaw.
udpRTPFrames: false
# Flag indicating UDP audio should follow the USRP format.
udpUsrp: false
# Source "Radio ID" for transmitted audio frames.
sourceId: 1234567

@ -5,6 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright (C) 2024-2025 Bryan Biedenkapp, N2PLL
* Copyright (C) 2025 Caleb, K4PHP
*
*/
#include "Defines.h"
@ -293,6 +294,7 @@ HostBridge::HostBridge(const std::string& confFile) :
m_udpNoIncludeLength(false),
m_udpUseULaw(false),
m_udpRTPFrames(false),
m_udpUsrp(false),
m_srcId(p25::defines::WUID_FNE),
m_srcIdOverride(0U),
m_overrideSrcIdFromMDC(false),
@ -353,7 +355,8 @@ HostBridge::HostBridge(const std::string& confFile) :
m_trace(false),
m_debug(false),
m_rtpSeqNo(0U),
m_rtpTimestamp(INVALID_TS)
m_rtpTimestamp(INVALID_TS),
m_usrpSeqNo(0U)
#if defined(_WIN32)
,
m_encoderState(nullptr),
@ -1019,10 +1022,19 @@ bool HostBridge::createNetwork()
m_udpReceivePort = (uint16_t)networkConf["udpReceivePort"].as<uint32_t>(34001);
m_udpReceiveAddress = networkConf["udpReceiveAddress"].as<std::string>();
m_udpUseULaw = networkConf["udpUseULaw"].as<bool>(false);
m_udpUsrp = networkConf["udpUsrp"].as<bool>(false);
if (m_udpUsrp) {
m_udpMetadata = false; // USRP disables metadata due to USRP always having metadata
m_udpRTPFrames = false; // USRP disables RTP
m_udpNoIncludeLength = true; // USRP disables length
m_udpUseULaw = false; // USRP disables ULaw
}
if (m_udpUseULaw) {
m_udpNoIncludeLength = networkConf["udpNoIncludeLength"].as<bool>(false);
m_udpRTPFrames = networkConf["udpRTPFrames"].as<bool>(false);
m_udpUsrp = false; // ULaw disables USRP
if (m_udpRTPFrames)
m_udpNoIncludeLength = true; // RTP disables the length being included
}
@ -1096,6 +1108,7 @@ bool HostBridge::createNetwork()
LogInfo(" UDP Audio No Length Header: %s", m_udpNoIncludeLength ? "yes" : "no");
LogInfo(" UDP Audio RTP Framed: %s", m_udpRTPFrames ? "yes" : "no");
}
LogInfo(" UDP Audio USRP: %s", m_udpUsrp ? "yes" : "no");
}
LogInfo(" Source ID: %u", m_srcId);
@ -1178,12 +1191,13 @@ void HostBridge::processUDPAudio()
pcmLength = __GET_UINT32(buffer, 0U);
}
if (m_udpRTPFrames)
if (m_udpRTPFrames || m_udpUsrp)
pcmLength = MBE_SAMPLES_LENGTH * 2U;
UInt8Array __pcm = std::make_unique<uint8_t[]>(pcmLength);
uint8_t* pcm = __pcm.get();
if (!m_udpUsrp) {
if (m_udpRTPFrames) {
RTPHeader rtpHeader = RTPHeader();
rtpHeader.decode(buffer);
@ -1203,6 +1217,14 @@ void HostBridge::processUDPAudio()
::memcpy(pcm, buffer + 4U, pcmLength);
}
}
}
else {
uint8_t* usrpHeader = new uint8_t[USRP_HEADER_LENGTH];
::memcpy(usrpHeader, buffer, USRP_HEADER_LENGTH);
if (usrpHeader[15U] == 1U && length > USRP_HEADER_LENGTH) // PTT state true and ensure we did not just receive a USRP header
::memcpy(pcm, buffer + USRP_HEADER_LENGTH, pcmLength);
}
// Utils::dump(1U, "PCM RECV BYTE BUFFER", pcm, pcmLength);
@ -1444,6 +1466,10 @@ void HostBridge::processDMRNetwork(uint8_t* buffer, uint32_t length)
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
uint64_t diff = now - m_rxStartTime;
// send USRP end of transmission
if (m_udpUsrp)
sendUsrpEot();
LogMessage(LOG_HOST, "P25, call end (T), srcId = %u, dstId = %u, dur = %us", srcId, dstId, diff / 1000U);
}
@ -1539,6 +1565,7 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
uint32_t length = (MBE_SAMPLES_LENGTH * 2U) + 4U;
uint8_t* audioData = nullptr;
if (!m_udpUsrp) {
if (!m_udpMetadata) {
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + 4U]; // PCM + 4 bytes (PCM length)
if (m_udpUseULaw) {
@ -1546,7 +1573,8 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
if (m_udpNoIncludeLength) {
length = MBE_SAMPLES_LENGTH;
::memcpy(audioData, pcm, MBE_SAMPLES_LENGTH);
} else {
}
else {
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
}
@ -1582,6 +1610,21 @@ void HostBridge::decodeDMRAudioFrame(uint8_t* ambe, uint32_t srcId, uint32_t dst
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
}
}
else {
uint8_t* usrpHeader = new uint8_t[USRP_HEADER_LENGTH];
length = (MBE_SAMPLES_LENGTH * 2U) + USRP_HEADER_LENGTH;
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + USRP_HEADER_LENGTH]; // PCM + 32 bytes (USRP Header)
m_usrpSeqNo++;
usrpHeader[15U] = 1; // set PTT state to true
__SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
::memcpy(usrpHeader, "USRP", 4);
::memcpy(audioData, usrpHeader, USRP_HEADER_LENGTH); // copy USRP header into the UDP payload
::memcpy(audioData + USRP_HEADER_LENGTH, pcm, MBE_SAMPLES_LENGTH * 2U);
}
sockaddr_storage addr;
uint32_t addrLen;
@ -1863,6 +1906,11 @@ void HostBridge::processP25Network(uint8_t* buffer, uint32_t length)
uint64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
uint64_t diff = now - m_rxStartTime;
// send USRP end of transmission
if (m_udpUsrp) {
sendUsrpEot();
}
LogMessage(LOG_HOST, "P25, call end, srcId = %u, dstId = %u, dur = %us", srcId, dstId, diff / 1000U);
}
@ -2130,6 +2178,8 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
uint32_t length = (MBE_SAMPLES_LENGTH * 2U) + 4U;
uint8_t* audioData = nullptr;
if (!m_udpUsrp) {
if (!m_udpMetadata) {
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + 4U]; // PCM + 4 bytes (PCM length)
if (m_udpUseULaw) {
@ -2137,7 +2187,8 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
if (m_udpNoIncludeLength) {
length = MBE_SAMPLES_LENGTH;
::memcpy(audioData, pcm, MBE_SAMPLES_LENGTH);
} else {
}
else {
__SET_UINT32(MBE_SAMPLES_LENGTH, audioData, 0U);
::memcpy(audioData + 4U, pcm, MBE_SAMPLES_LENGTH);
}
@ -2173,6 +2224,21 @@ void HostBridge::decodeP25AudioFrame(uint8_t* ldu, uint32_t srcId, uint32_t dstI
__SET_UINT32(dstId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 4U));
__SET_UINT32(srcId, audioData, ((MBE_SAMPLES_LENGTH * 2U) + 8U));
}
}
else {
uint8_t* usrpHeader = new uint8_t[USRP_HEADER_LENGTH];
length = (MBE_SAMPLES_LENGTH * 2U) + USRP_HEADER_LENGTH;
audioData = new uint8_t[(MBE_SAMPLES_LENGTH * 2U) + USRP_HEADER_LENGTH]; // PCM + 32 bytes (USRP Header)
m_usrpSeqNo++;
usrpHeader[15U] = 1; // set PTT state to true
__SET_UINT32(m_usrpSeqNo, usrpHeader, 4U);
::memcpy(usrpHeader, "USRP", 4);
::memcpy(audioData, usrpHeader, USRP_HEADER_LENGTH); // copy USRP header into the UDP payload
::memcpy(audioData + USRP_HEADER_LENGTH, pcm, MBE_SAMPLES_LENGTH * 2U);
}
sockaddr_storage addr;
uint32_t addrLen;
@ -2341,6 +2407,22 @@ void HostBridge::encodeP25AudioFrame(uint8_t* pcm, uint32_t forcedSrcId, uint32_
m_p25N++;
}
/* Helper to send USRP end of transmission */
void HostBridge::sendUsrpEot() {
sockaddr_storage addr;
uint32_t addrLen;
uint8_t* usrpHeader = new uint8_t[USRP_HEADER_LENGTH];
m_usrpSeqNo = 0U;
::memcpy(usrpHeader, "USRP", 4);
if (udp::Socket::lookup(m_udpSendAddress, m_udpSendPort, addr, addrLen) == 0) {
m_udpAudioSocket->write(usrpHeader, USRP_HEADER_LENGTH, addr, addrLen);
}
}
/* Helper to generate the single-tone preamble tone. */
void HostBridge::generatePreambleTone()

@ -56,6 +56,8 @@
#define DECSTATE_SIZE 2048
#define ENCSTATE_SIZE 6144
#define USRP_HEADER_LENGTH 32
const uint8_t FULL_RATE_MODE = 0x00U;
const uint8_t HALF_RATE_MODE = 0x01U;
@ -162,6 +164,7 @@ private:
bool m_udpNoIncludeLength;
bool m_udpUseULaw;
bool m_udpRTPFrames;
bool m_udpUsrp;
uint32_t m_srcId;
uint32_t m_srcIdOverride;
@ -245,6 +248,8 @@ private:
uint16_t m_rtpSeqNo;
uint32_t m_rtpTimestamp;
uint32_t m_usrpSeqNo;
static std::mutex m_audioMutex;
static std::mutex m_networkMutex;
@ -446,6 +451,11 @@ private:
*/
uint8_t* generateRTPHeaders(uint8_t msgLen, uint16_t& rtpSeq);
/**
* @brief Helper to generate USRP end of transmission
*/
void sendUsrpEot();
/**
* @brief Helper to generate the single-tone preamble tone.
*/

Loading…
Cancel
Save

Powered by TurnKey Linux.