Add IMBE transcode for P25

main
Doug McLain 3 years ago
parent 9269fefa56
commit 955d126058

@ -1,5 +1,6 @@
// tcd - a hybid transcoder using DVSI hardware and Codec2 software
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2021 Doug McLain AD8DP
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -23,6 +24,7 @@
#include <thread>
#include <md380_vocoder.h>
#include "TranscoderPacket.h"
#include "Controller.h"
@ -54,6 +56,7 @@ bool CController::Start()
reflectorFuture = std::async(std::launch::async, &CController::ReadReflectorThread, this);
c2Future = std::async(std::launch::async, &CController::ProcessC2Thread, this);
swambe2Future = std::async(std::launch::async, &CController::ProcessSWAMBE2Thread,this);
imbeFuture = std::async(std::launch::async, &CController::ProcessIMBEThread,this);
return false;
}
@ -260,6 +263,9 @@ void CController::ReadReflectorThread()
else
dmrsf_device->AddPacket(packet);
break;
case ECodecType::p25:
imbe_queue.push(packet);
break;
case ECodecType::c2_1600:
case ECodecType::c2_3200:
codec2_queue.push(packet);
@ -308,6 +314,7 @@ void CController::AudiotoCodec2(std::shared_ptr<CTranscoderPacket> packet)
void CController::Codec2toAudio(std::shared_ptr<CTranscoderPacket> packet)
{
uint8_t ambe2[9];
uint8_t imbe[11];
if (packet->IsSecond())
{
@ -354,6 +361,8 @@ void CController::Codec2toAudio(std::shared_ptr<CTranscoderPacket> packet)
md380_encode_fec(ambe2, packet->GetAudioSamples());
packet->SetDMRData(ambe2);
p25vocoder.encode_4400((int16_t*)packet->GetAudioSamples(), imbe);
packet->SetP25Data(imbe);
}
void CController::ProcessC2Thread()
@ -373,6 +382,7 @@ void CController::ProcessC2Thread()
case ECodecType::dstar:
case ECodecType::dmr:
case ECodecType::p25:
// codec_in was AMBE, so we need to calculate the the M17 data
AudiotoCodec2(packet);
break;
@ -413,6 +423,7 @@ void CController::SWAMBE2toAudio(std::shared_ptr<CTranscoderPacket> packet)
packet->SetAudioSamples(tmp, false);
dstar_device->AddPacket(packet);
codec2_queue.push(packet);
imbe_queue.push(packet);
}
void CController::ProcessSWAMBE2Thread()
@ -426,6 +437,7 @@ void CController::ProcessSWAMBE2Thread()
case ECodecType::c2_1600:
case ECodecType::c2_3200:
case ECodecType::dstar:
case ECodecType::p25:
AudiotoSWAMBE2(packet);
break;
@ -436,6 +448,64 @@ void CController::ProcessSWAMBE2Thread()
}
}
void CController::AudiotoIMBE(std::shared_ptr<CTranscoderPacket> packet)
{
const auto m = packet->GetModule();
uint8_t imbe[11];
int16_t tmp[160];
const int16_t *p = packet->GetAudioSamples();
const uint32_t g = abs(gain);
for(int i = 0; i < 160; ++i){
if(gain < 0){
tmp[i] = p[i] / g;
}
else{
tmp[i] = p[i] * g;
}
}
p25vocoder.encode_4400(tmp, imbe);
packet->SetP25Data(imbe);
// we might be all done...
send_mux.lock();
if (packet->AllCodecsAreSet() && packet->HasNotBeenSent()) SendToReflector(packet);
send_mux.unlock();
}
void CController::IMBEtoAudio(std::shared_ptr<CTranscoderPacket> packet)
{
int16_t tmp[160] = {0};
p25vocoder.decode_4400(tmp, (uint8_t*)packet->GetP25Data());
packet->SetAudioSamples(tmp, false);
dstar_device->AddPacket(packet);
codec2_queue.push(packet);
swambe2_queue.push(packet);
}
void CController::ProcessIMBEThread()
{
while (keep_running)
{
auto packet = imbe_queue.pop();
switch (packet->GetCodecIn())
{
case ECodecType::c2_1600:
case ECodecType::c2_3200:
case ECodecType::dstar:
case ECodecType::dmr:
AudiotoIMBE(packet);
break;
case ECodecType::p25:
IMBEtoAudio(packet);
break;
}
}
}
void CController::SendToReflector(std::shared_ptr<CTranscoderPacket> packet)
{
// open a socket to the reflector channel
@ -455,6 +525,7 @@ void CController::RouteDstPacket(std::shared_ptr<CTranscoderPacket> packet)
{
// codec_in is dstar, the audio has just completed, so now calc the M17 and DMR
codec2_queue.push(packet);
imbe_queue.push(packet);
if(swambe2)
swambe2_queue.push(packet);
else
@ -473,6 +544,7 @@ void CController::RouteDmrPacket(std::shared_ptr<CTranscoderPacket> packet)
if (ECodecType::dmr == packet->GetCodecIn())
{
codec2_queue.push(packet);
imbe_queue.push(packet);
dstar_device->AddPacket(packet);
}
else

@ -2,6 +2,7 @@
// tcd - a hybid transcoder using DVSI hardware and Codec2 software
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2021 Doug McLain AD8DP
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -23,6 +24,7 @@
#include <mutex>
#include <list>
#include <utility>
#include <imbe_vocoder_api.h>
#include "codec2.h"
#include "DV3000.h"
@ -44,7 +46,7 @@ public:
protected:
std::atomic<bool> keep_running;
std::future<void> reflectorFuture, c2Future, swambe2Future;
std::future<void> reflectorFuture, c2Future, swambe2Future, imbeFuture;
std::unordered_map<char, int16_t[160]> audio_store;
std::unordered_map<char, uint8_t[8]> data_store;
CUnixDgramReader reader;
@ -54,9 +56,11 @@ protected:
CPacketQueue codec2_queue;
CPacketQueue swambe2_queue;
CPacketQueue imbe_queue;
std::mutex send_mux;
int16_t gain;
bool swambe2;
imbe_vocoder p25vocoder;
bool DiscoverFtdiDevices(std::list<std::pair<std::string, std::string>> &found);
bool InitVocoders();
@ -64,9 +68,12 @@ protected:
void ReadReflectorThread();
void ProcessC2Thread();
void ProcessSWAMBE2Thread();
void ProcessIMBEThread();
void Codec2toAudio(std::shared_ptr<CTranscoderPacket> packet);
void AudiotoCodec2(std::shared_ptr<CTranscoderPacket> packet);
void SWAMBE2toAudio(std::shared_ptr<CTranscoderPacket> packet);
void AudiotoSWAMBE2(std::shared_ptr<CTranscoderPacket> packet);
void IMBEtoAudio(std::shared_ptr<CTranscoderPacket> packet);
void AudiotoIMBE(std::shared_ptr<CTranscoderPacket> packet);
void SendToReflector(std::shared_ptr<CTranscoderPacket> packet);
};

@ -14,7 +14,7 @@ else
CFLAGS = -W -Werror -Icodec2 -MMD -MD -std=c++11
endif
LDFLAGS = -lftd2xx -lmd380_vocoder -pthread
LDFLAGS = -lftd2xx -lmd380_vocoder -limbe_vocoder -pthread
SRCS = $(wildcard *.cpp) $(wildcard codec2/*.cpp)
OBJS = $(SRCS:.cpp=.o)

@ -19,7 +19,7 @@
#include "TranscoderPacket.h"
CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), dmr_set(false), m17_set(false), not_sent(true)
CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), dmr_set(false), p25_set(false), m17_set(false), not_sent(true)
{
tcpacket.module = tcp.module;
tcpacket.is_last = tcp.is_last;
@ -34,6 +34,9 @@ CTranscoderPacket::CTranscoderPacket(const STCPacket &tcp) : dstar_set(false), d
case ECodecType::dmr:
SetDMRData(tcp.dmr);
break;
case ECodecType::p25:
SetP25Data(tcp.p25);
break;
case ECodecType::c2_1600:
case ECodecType::c2_3200:
SetM17Data(tcp.m17);
@ -59,6 +62,11 @@ const uint8_t *CTranscoderPacket::GetDMRData() const
return tcpacket.dmr;
}
const uint8_t *CTranscoderPacket::GetP25Data() const
{
return tcpacket.p25;
}
const uint8_t *CTranscoderPacket::GetM17Data() const
{
return tcpacket.m17;
@ -87,6 +95,12 @@ void CTranscoderPacket::SetDMRData(const uint8_t *dmr)
dmr_set = true;
}
void CTranscoderPacket::SetP25Data(const uint8_t *p25)
{
memcpy(tcpacket.p25, p25, 11);
p25_set = true;
}
void CTranscoderPacket::SetAudioSamples(const int16_t *sample, bool swap)
{
for (unsigned int i=0; i<160; i++)
@ -138,6 +152,11 @@ bool CTranscoderPacket::DMRIsSet() const
return dmr_set;
}
bool CTranscoderPacket::P25IsSet() const
{
return p25_set;
}
bool CTranscoderPacket::M17IsSet() const
{
return m17_set;
@ -145,7 +164,7 @@ bool CTranscoderPacket::M17IsSet() const
bool CTranscoderPacket::AllCodecsAreSet() const
{
return (dstar_set && dmr_set && m17_set);
return (dstar_set && dmr_set && m17_set && p25_set);
}
void CTranscoderPacket::Sent()

@ -35,9 +35,11 @@ public:
// codec
const uint8_t *GetDStarData() const;
const uint8_t *GetDMRData() const;
const uint8_t *GetP25Data() const;
const uint8_t *GetM17Data() const;
void SetDStarData(const uint8_t *dstar);
void SetDMRData(const uint8_t *dmr);
void SetP25Data(const uint8_t *p25);
void SetM17Data(const uint8_t *m17);
void SetAudioSamples(const int16_t *samples, bool swap);
@ -53,6 +55,7 @@ public:
bool IsSecond() const;
bool DStarIsSet() const;
bool DMRIsSet() const;
bool P25IsSet() const;
bool M17IsSet() const;
bool AllCodecsAreSet() const;
void Sent();
@ -64,5 +67,5 @@ public:
private:
STCPacket tcpacket;
int16_t audio[160];
std::atomic_bool dstar_set, dmr_set, m17_set, not_sent;
std::atomic_bool dstar_set, dmr_set, p25_set, m17_set, not_sent;
};

Loading…
Cancel
Save

Powered by TurnKey Linux.