From b08629a896fd65f5cce1f389c3e59cd7606dcac3 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 7 Nov 2026 17:39:03 -0500 Subject: [PATCH] support Linux versions of the AMBE library as well; --- src/bridge/HostBridge.cpp | 86 +++++++++++++++++++++++++++++---------- src/bridge/HostBridge.h | 41 +++++++++++++------ 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/src/bridge/HostBridge.cpp b/src/bridge/HostBridge.cpp index 1637bc2d..123dffa5 100644 --- a/src/bridge/HostBridge.cpp +++ b/src/bridge/HostBridge.cpp @@ -53,6 +53,7 @@ using namespace network::udp; #if !defined(_WIN32) #include #include +#include #endif // !defined(_WIN32) // --------------------------------------------------------------------------- @@ -283,20 +284,20 @@ HostBridge::HostBridge(const std::string& confFile) : m_rtpTimestamp(INVALID_TS), m_udpNetPktSeq(0U), m_udpNetLastPktSeq(0U), - m_usrpSeqNo(0U) -#if defined(_WIN32) - , + m_usrpSeqNo(0U), m_decoderState(nullptr), m_dcMode(0U), m_encoderState(nullptr), m_ecMode(0U), - m_ambeDLL(nullptr), m_useExternalVocoder(false), m_frameLengthInBits(0), - m_frameLengthInBytes(0) + m_frameLengthInBytes(0), +#if defined(_WIN32) + m_ambeDLL(nullptr) +#else + m_ambeHandle(nullptr) #endif // defined(_WIN32) { -#if defined(_WIN32) ambe_init_dec = nullptr; ambe_get_dec_mode = nullptr; ambe_voice_dec = nullptr; @@ -304,7 +305,7 @@ HostBridge::HostBridge(const std::string& confFile) : ambe_init_enc = nullptr; ambe_get_enc_mode = nullptr; ambe_voice_enc = nullptr; -#endif // defined(_WIN32) + m_ambeBuffer = new uint8_t[27U]; ::memset(m_ambeBuffer, 0x00U, 27U); @@ -538,6 +539,9 @@ int HostBridge::run() #if defined(_WIN32) initializeAMBEDLL(); +#else + initializeAMBELib(); +#endif // defined(_WIN32) if (m_useExternalVocoder) { m_decoderState = ::malloc(DECSTATE_SIZE); ::memset(m_decoderState, 0x00U, DECSTATE_SIZE); @@ -562,7 +566,6 @@ int HostBridge::run() ambe_init_enc(m_encoderState, HALF_RATE_MODE, 1); } } -#endif // defined(_WIN32) // set the In-Call Control function callback if (m_network != nullptr) { @@ -762,13 +765,20 @@ int HostBridge::run() delete m_mdcDecoder; + if (m_encoderState != nullptr) { + free(m_encoderState); + m_encoderState = nullptr; + } + if (m_decoderState != nullptr) { + free(m_decoderState); + m_decoderState = nullptr; + } #if defined(_WIN32) - if (m_encoderState != nullptr) - delete m_encoderState; - if (m_decoderState != nullptr) - delete m_decoderState; if (m_ambeDLL != nullptr) ::FreeLibrary(m_ambeDLL); +#else + if (m_ambeHandle != nullptr) + dlclose(m_ambeHandle); #endif // defined(_WIN32) if (m_localAudio) { @@ -793,6 +803,9 @@ void HostBridge::initializeAMBEDLL() // get a handle to the DLL module. m_ambeDLL = LoadLibrary(TEXT("AMBE.dll")); + if (m_ambeDLL == nullptr) + m_ambeDLL = LoadLibrary(TEXT("ambe_native.dll")); + if (m_ambeDLL != nullptr) { ambe_init_dec = (Tambe_init_dec)GetProcAddress(m_ambeDLL, "ambe_init_dec"); @@ -807,6 +820,36 @@ void HostBridge::initializeAMBEDLL() m_useExternalVocoder = true; } } +#else +/* Helper to initialize the use of the external AMBE binary for DVSI USB-3000. */ + +void HostBridge::initializeAMBELib() +{ + m_useExternalVocoder = false; + + m_ambeHandle = dlopen("libambe.so", RTLD_LAZY); + if (m_ambeHandle == nullptr) + m_ambeHandle = dlopen("./libambe.so", RTLD_LAZY); + if (m_ambeHandle == nullptr) + m_ambeHandle = dlopen("libambe_native.so", RTLD_LAZY); + if (m_ambeHandle == nullptr) + m_ambeHandle = dlopen("./libambe_native.so", RTLD_LAZY); + + if (m_ambeHandle != nullptr) + { + ambe_init_dec = (Tambe_init_dec)dlsym(m_ambeHandle, "ambe_init_dec"); + ambe_get_dec_mode = (Tambe_get_dec_mode)dlsym(m_ambeHandle, "ambe_get_dec_mode"); + ambe_voice_dec = (Tambe_voice_dec)dlsym(m_ambeHandle, "ambe_voice_dec"); + + ambe_init_enc = (Tambe_init_enc)dlsym(m_ambeHandle, "ambe_init_enc"); + ambe_get_enc_mode = (Tambe_get_enc_mode)dlsym(m_ambeHandle, "ambe_get_enc_mode"); + ambe_voice_enc = (Tambe_voice_enc)dlsym(m_ambeHandle, "ambe_voice_enc"); + + ::LogInfoEx(LOG_HOST, "Using external USB vocoder."); + m_useExternalVocoder = true; + } +} +#endif // defined(_WIN32) /* Helper to unpack the codeword bytes into codeword bits for use with the AMBE decoder. */ @@ -869,7 +912,7 @@ int HostBridge::ambeDecode(const uint8_t* codeword, uint32_t codewordLength, sho ::memcpy(cw.get(), codeword, codewordLength); // is this a DMR codeword? - if (codewordLength > m_frameLengthInBytes && (m_txMode == TX_MODE_DMR || m_txMode == TX_MODE_NXDN) && + if (codewordLength > (uint32_t)m_frameLengthInBytes && (m_txMode == TX_MODE_DMR || m_txMode == TX_MODE_NXDN) && codewordLength == 9) { // use the vocoder to retrieve the un-ECC'ed and uninterleaved AMBE bits @@ -881,13 +924,13 @@ int HostBridge::ambeDecode(const uint8_t* codeword, uint32_t codewordLength, sho codewordLength = m_frameLengthInBytes; } - if (codewordLength > m_frameLengthInBytes) { - ::LogError(LOG_HOST, "Codeword length is > %u", m_frameLengthInBytes); + if (codewordLength > (uint32_t)m_frameLengthInBytes) { + ::LogError(LOG_HOST, "Codeword length is > %u", (uint32_t)m_frameLengthInBytes); return -1; } - if (codewordLength < m_frameLengthInBytes) { - ::LogError(LOG_HOST, "Codeword length is < %u", m_frameLengthInBytes); + if (codewordLength < (uint32_t)m_frameLengthInBytes) { + ::LogError(LOG_HOST, "Codeword length is < %u", (uint32_t)m_frameLengthInBytes); return -1; } @@ -902,9 +945,9 @@ int HostBridge::ambeDecode(const uint8_t* codeword, uint32_t codewordLength, sho ambe_voice_dec(n1.get(), AUDIO_SAMPLES_LENGTH / 2, codewordBits.get(), NO_BIT_STEAL, m_dcMode, 1, m_decoderState); // combine sample segments into contiguous samples - for (int i = 0; i < AUDIO_SAMPLES_LENGTH / 2; i++) + for (int i = 0; i < (int)AUDIO_SAMPLES_LENGTH / 2; i++) samples[i] = n0[i]; - for (int i = 0; i < AUDIO_SAMPLES_LENGTH / 2; i++) + for (int i = 0; i < (int)AUDIO_SAMPLES_LENGTH / 2; i++) samples[i + (AUDIO_SAMPLES_LENGTH / 2)] = n1[i]; return 0; // this always just returns no errors? @@ -982,13 +1025,13 @@ void HostBridge::ambeEncode(const short* samples, uint32_t sampleLength, uint8_t // split samples into 2 segments std::unique_ptr n0 = std::make_unique(AUDIO_SAMPLES_LENGTH / 2); - for (int i = 0; i < AUDIO_SAMPLES_LENGTH / 2; i++) + for (int i = 0; i < (int)AUDIO_SAMPLES_LENGTH / 2; i++) n0[i] = samples[i]; ambe_voice_enc(codewordBits.get(), NO_BIT_STEAL, n0.get(), AUDIO_SAMPLES_LENGTH / 2, m_ecMode, 0, 8192, m_encoderState); std::unique_ptr n1 = std::make_unique(AUDIO_SAMPLES_LENGTH / 2); - for (int i = 0; i < AUDIO_SAMPLES_LENGTH / 2; i++) + for (int i = 0; i < (int)AUDIO_SAMPLES_LENGTH / 2; i++) n1[i] = samples[i + (AUDIO_SAMPLES_LENGTH / 2)]; ambe_voice_enc(codewordBits.get(), NO_BIT_STEAL, n1.get(), AUDIO_SAMPLES_LENGTH / 2, m_ecMode, 1, 8192, m_encoderState); @@ -1007,7 +1050,6 @@ void HostBridge::ambeEncode(const short* samples, uint32_t sampleLength, uint8_t packBitsToBytes(codewordBits.get(), codeword, m_frameLengthInBytes, m_frameLengthInBits); } } -#endif // defined(_WIN32) /* Reads basic configuration parameters from the YAML configuration file. */ diff --git a/src/bridge/HostBridge.h b/src/bridge/HostBridge.h index 2a49e4df..f03b5e1d 100644 --- a/src/bridge/HostBridge.h +++ b/src/bridge/HostBridge.h @@ -327,19 +327,45 @@ private: static std::mutex s_audioMutex; static std::mutex s_networkMutex; -#if defined(_WIN32) void* m_decoderState; uint16_t m_dcMode; void* m_encoderState; uint16_t m_ecMode; - HINSTANCE m_ambeDLL; bool m_useExternalVocoder; int m_frameLengthInBits; int m_frameLengthInBytes; +#if defined(_WIN32) + HINSTANCE m_ambeDLL; + typedef void(__cdecl* Tambe_init_dec)(void* state, short mode); + typedef short(__cdecl* Tambe_get_dec_mode)(void* state); + typedef uint32_t(__cdecl* Tambe_voice_dec)(short* samples, short sampleLength, short* packedCodeword, short bitSteal, uint16_t cmode, short n, void* state); + typedef void(__cdecl* Tambe_init_enc)(void* state, short mode, short initialize); + typedef short(__cdecl* Tambe_get_enc_mode)(void* state); + typedef uint32_t(__cdecl* Tambe_voice_enc)(short* packedCodeword, short bitSteal, short* samples, short sampleLength, uint16_t cmode, short n, short, void* state); + + /** + * @brief Helper to initialize the use of the external AMBE.DLL binary for DVSI USB-3000. + */ + void initializeAMBEDLL(); +#else + void* m_ambeHandle; + + typedef void(*Tambe_init_dec)(void* state, short mode); + typedef short(*Tambe_get_dec_mode)(void* state); + typedef uint32_t(*Tambe_voice_dec)(short* samples, short sampleLength, short* packedCodeword, short bitSteal, uint16_t cmode, short n, void* state); + typedef void(*Tambe_init_enc)(void* state, short mode, short initialize); + typedef short(*Tambe_get_enc_mode)(void* state); + typedef uint32_t(*Tambe_voice_enc)(short* packedCodeword, short bitSteal, short* samples, short sampleLength, uint16_t cmode, short n, short, void* state); + + /** + * @brief Helper to initialize the use of the external AMBE binary for DVSI USB-3000. + */ + void initializeAMBELib(); +#endif // defined(_WIN32) /** * @brief Initialize the AMBE decoder. * @param[out] state Buffer containing the decoder state to initialize. @@ -347,7 +373,6 @@ private: */ Tambe_init_dec ambe_init_dec; - typedef short(__cdecl* Tambe_get_dec_mode)(void* state); /** * @brief Get the current operating state of the AMBE decoder. * @param[out] state Buffer containing the decoder state. @@ -355,7 +380,6 @@ private: */ Tambe_get_dec_mode ambe_get_dec_mode; - typedef uint32_t(__cdecl* Tambe_voice_dec)(short* samples, short sampleLength, short* packedCodeword, short bitSteal, uint16_t cmode, short n, void* state); /** * @brief Decode AMBE codeword into PCM samples. * @param[out] samples Audio Output (in short samples) @@ -369,7 +393,6 @@ private: */ Tambe_voice_dec ambe_voice_dec; - typedef void(__cdecl* Tambe_init_enc)(void* state, short mode, short initialize); /** * @brief Initialize the AMBE decoder. * @param[out] state Buffer containing the ebncoder state to initialize. @@ -378,7 +401,6 @@ private: */ Tambe_init_enc ambe_init_enc; - typedef short(__cdecl* Tambe_get_enc_mode)(void* state); /** * @brief Get the current operating state of the AMBE encoder. * @param[out] state Buffer containing the decoder state. @@ -386,7 +408,6 @@ private: */ Tambe_get_enc_mode ambe_get_enc_mode; - typedef uint32_t(__cdecl* Tambe_voice_enc)(short* packedCodeword, short bitSteal, short* samples, short sampleLength, uint16_t cmode, short n, short, void* state); /** * @brief Decode AMBE codeword into PCM samples. * @param[out] packedCodeword AMBE codewords. @@ -401,11 +422,6 @@ private: */ Tambe_voice_enc ambe_voice_enc; - /** - * @brief Helper to initialize the use of the external AMBE.DLL binary for DVSI USB-3000. - */ - void initializeAMBEDLL(); - /** * @brief Helper to unpack the codeword bytes into codeword bits for use with the AMBE decoder. * @param[out] codewordBits Codeword bits. @@ -455,7 +471,6 @@ private: * @returns int */ void ambeEncode(const short* samples, uint32_t sampleLength, uint8_t* codeword); -#endif // defined(_WIN32) /** * @brief Reads basic configuration parameters from the INI.