Support Codec 2 mode 2400 with added FEC

The "vocoder extension" by SV9OAN, for using the open source Codec 2 with D-STAR has been extended to include a mode for FEC (https://github.com/chazapis/pydv). With Codec 2 mode 2400, each encoded voice fragment fits into just 6 bytes. The 3 remaining bytes are used to protect the first 24 bits of the voice data with two applications of the (23, 12) Golay code.

Code changes include defining a new codec in both xlxd and ambed. In ambed, every Codec 2 interface has now one channel for each Codec 2 mode. Also, channel groups have an additional channel, as Codec 2 mode 2400 is used only as input.
pull/118/head
Antony Chazapis 7 years ago
parent 9581d729a7
commit 635335eabb

@ -29,6 +29,7 @@
#include "cvoicepacket.h"
#include "ccodec2interface.h"
#include "cvocodecchannel.h"
#include <codec2/golay23.h>
////////////////////////////////////////////////////////////////////////////////////////
@ -43,7 +44,8 @@ CCodec2Interface::CCodec2Interface()
CCodec2Interface::~CCodec2Interface()
{
codec2_destroy(codec2_state);
codec2_destroy(codec2_3200_state);
codec2_destroy(codec2_2400_state);
}
////////////////////////////////////////////////////////////////////////////////////////
@ -54,8 +56,9 @@ bool CCodec2Interface::Init(void)
bool ok = true;
// create codec state
codec2_state = codec2_create(CODEC2_MODE_3200);
if (codec2_state == NULL)
codec2_3200_state = codec2_create(CODEC2_MODE_3200);
codec2_2400_state = codec2_create(CODEC2_MODE_2400);
if (codec2_3200_state == NULL || codec2_2400_state == NULL)
{
ok = false;
}
@ -70,6 +73,14 @@ bool CCodec2Interface::Init(void)
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// manage Channels
uint8 CCodec2Interface::GetChannelCodec(int iCh) const
{
return (iCh == 0) ? CODEC_CODEC2_3200 : CODEC_CODEC2_2400;
}
////////////////////////////////////////////////////////////////////////////////////////
// task
@ -107,9 +118,9 @@ void CCodec2Interface::Task(void)
if ( Packet != NULL )
{
// this is second step of transcoding
// we just received from a decoded speech packet
// we just received a decoded speech packet
// encode and cpush back to relevant channel outcoming queue
EncodeVoicePacket(Packet, &AmbePacket);
EncodeVoicePacket(Packet, &AmbePacket, GetChannelCodec(i));
AmbePacket.SetPid(Packet->GetPid());
delete Packet;
@ -124,7 +135,7 @@ void CCodec2Interface::Task(void)
}
}
// any packet in voice queue 1 ?
// any packet in voice queue 2 ?
if ( Channel != NULL && Channel->IsInterfaceOut2(this) )
{
CVoicePacket *Packet = NULL;
@ -141,9 +152,9 @@ void CCodec2Interface::Task(void)
if ( Packet != NULL )
{
// this is second step of transcoding
// we just received from a decoded speech packet
// we just received a decoded speech packet
// encode and cpush back to relevant channel outcoming queue
EncodeVoicePacket(Packet, &AmbePacket);
EncodeVoicePacket(Packet, &AmbePacket, GetChannelCodec(i));
AmbePacket.SetPid(Packet->GetPid());
delete Packet;
@ -180,7 +191,7 @@ void CCodec2Interface::Task(void)
// this is first step of transcoding
// a fresh new packet to be transcoded is showing up
// decode and copy the result into both voice queues
DecodeAmbePacket(Packet, &VoicePacket);
DecodeAmbePacket(Packet, &VoicePacket, GetChannelCodec(i));
VoicePacket.SetPid(Packet->GetPid());
delete Packet;
@ -210,11 +221,45 @@ void CCodec2Interface::Task(void)
////////////////////////////////////////////////////////////////////////////////////////
// decoder helper
void CCodec2Interface::DecodeAmbePacket(CAmbePacket *PacketIn, CVoicePacket *PacketOut)
void CCodec2Interface::DecodeAmbePacket(CAmbePacket *PacketIn, CVoicePacket *PacketOut, uint8 Codec)
{
unsigned char ambe[AMBE_SIZE];
struct CODEC2 *codec2_state;
short voice[160];
codec2_decode(codec2_state, voice, (unsigned char *)PacketIn->GetAmbe());
::memcpy(ambe, (unsigned char *)PacketIn->GetAmbe(), AMBE_SIZE);
if ( Codec == CODEC_CODEC2_2400 )
{
uint32 received_codeword;
uint32 corrected_codeword;
uint8 partial_byte;
// unsigned int bit_errors = 0;
received_codeword = ((ambe[0] << 15) |
(((ambe[1] >> 4) & 0x0F) << 11) |
(ambe[6] << 3) |
((ambe[7] >> 5) & 0x07));
corrected_codeword = golay23_decode(received_codeword);
// bit_errors += golay23_count_errors(received_codeword, corrected_codeword);
ambe[0] = (uint8)((corrected_codeword >> 15) & 0xFF);
partial_byte = (uint8)(((corrected_codeword >> 11) & 0x0F) << 4);
received_codeword = (((ambe[1] & 0x0F) << 19) |
(ambe[2] << 11) |
((ambe[7] & 0x1F) << 6) |
((ambe[8] >> 2) & 0x3F));
corrected_codeword = golay23_decode(received_codeword);
// bit_errors += golay23_count_errors(received_codeword, corrected_codeword);
// std::cout << "Packet decoded with " << bit_errors << " bit errors" << std::endl;
ambe[1] = partial_byte | (uint8)((corrected_codeword >> 19) & 0x0F);
ambe[2] = (uint8)((corrected_codeword >> 11) & 0xFF);
}
codec2_state = (Codec == CODEC_CODEC2_3200) ? codec2_3200_state : codec2_2400_state;
codec2_decode(codec2_state, voice, ambe);
for ( int i = 0; i < 160; i++ )
{
voice[i] = MAKEWORD(HIBYTE(voice[i]), LOBYTE(voice[i]));
@ -225,8 +270,14 @@ void CCodec2Interface::DecodeAmbePacket(CAmbePacket *PacketIn, CVoicePacket *Pac
////////////////////////////////////////////////////////////////////////////////////////
// encoder helpers
void CCodec2Interface::EncodeVoicePacket(CVoicePacket *PacketIn, CAmbePacket *PacketOut)
void CCodec2Interface::EncodeVoicePacket(CVoicePacket *PacketIn, CAmbePacket *PacketOut, uint8 Codec)
{
// Output always in mode 3200.
if ( Codec != CODEC_CODEC2_3200 )
{
return;
}
unsigned char ambe[AMBE_SIZE];
short voice[160];
@ -235,8 +286,8 @@ void CCodec2Interface::EncodeVoicePacket(CVoicePacket *PacketIn, CAmbePacket *Pa
{
voice[i] = MAKEWORD(HIBYTE(voice[i]), LOBYTE(voice[i]));
}
codec2_encode(codec2_state, ambe, voice);
codec2_encode(codec2_3200_state, ambe, voice);
ambe[8] = 0x00;
PacketOut->SetCodec(CODEC_CODEC2);
PacketOut->SetCodec(CODEC_CODEC2_3200);
PacketOut->SetAmbe((uint8 *)ambe);
}

@ -47,21 +47,22 @@ public:
const char *GetName(void) const { return "Codec 2"; }
// manage channels
int GetNbChannels(void) const { return 1; }
uint8 GetChannelCodec(int) const { return CODEC_CODEC2; }
int GetNbChannels(void) const { return 2; }
uint8 GetChannelCodec(int) const;
// task
void Task(void);
protected:
// decoder helper
void DecodeAmbePacket(CAmbePacket *, CVoicePacket *);
void DecodeAmbePacket(CAmbePacket *, CVoicePacket *, uint8);
// encoder helpers
void EncodeVoicePacket(CVoicePacket *, CAmbePacket *);
void EncodeVoicePacket(CVoicePacket *, CAmbePacket *, uint8);
// data
struct CODEC2 *codec2_state;
struct CODEC2 *codec2_3200_state;
struct CODEC2 *codec2_2400_state;
};
////////////////////////////////////////////////////////////////////////////////////////

@ -363,13 +363,16 @@ void CController::EncodeNoStreamAvailablePacket(CBuffer *Buffer)
bool CController::IsValidCodecIn(uint8 codec)
{
return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) || (codec == CODEC_CODEC2));
return ((codec == CODEC_AMBEPLUS) ||
(codec == CODEC_AMBE2PLUS) ||
(codec == CODEC_CODEC2_3200) ||
(codec == CODEC_CODEC2_2400));
}
bool CController::IsValidCodecsOut(uint8 codec)
{
return ((codec == (CODEC_AMBEPLUS | CODEC_CODEC2)) ||
(codec == (CODEC_AMBE2PLUS | CODEC_CODEC2)) ||
return ((codec == (CODEC_AMBEPLUS | CODEC_CODEC2_3200)) ||
(codec == (CODEC_AMBE2PLUS | CODEC_CODEC2_3200)) ||
(codec == (CODEC_AMBEPLUS | CODEC_AMBE2PLUS)));
}

@ -197,20 +197,30 @@ int CFtdiDeviceDescr::GetNbChannels(void) const
////////////////////////////////////////////////////////////////////////////////////////
// factory helper
void CFtdiDeviceDescr::CreateChannelGroup(CVocodecInterface *InterfaceAmbe, int ChannelAmbe, CVocodecInterface *InterfaceAmbePlus, int ChannelAmbePlus, CVocodecInterface *InterfaceCodec2, int ChannelCodec2, std::vector<CVocodecChannel *>*channels)
{
CVocodecChannel *ChannelA = new CVocodecChannel(InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, InterfaceCodec2, ChannelCodec2, CODECGAIN_AMBEPLUS);
CVocodecChannel *ChannelB = new CVocodecChannel(InterfaceAmbePlus, ChannelAmbePlus, InterfaceAmbe, ChannelAmbe, InterfaceCodec2, ChannelCodec2, CODECGAIN_AMBE2PLUS);
CVocodecChannel *ChannelC = new CVocodecChannel(InterfaceCodec2, ChannelCodec2, InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, CODECGAIN_CODEC2);
void CFtdiDeviceDescr::CreateChannelGroup(CVocodecInterface *InterfaceAmbe, int ChannelAmbe, CVocodecInterface *InterfaceAmbePlus, int ChannelAmbePlus, CVocodecInterface *InterfaceCodec2, std::vector<CVocodecChannel *>*channels)
{
// The Codec 2 interface has two channels: 0 for mode 3200, 1 for mode 2400.
// Use both for input, but only channel 0 for output.
CVocodecChannel *ChannelA = new CVocodecChannel(InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, InterfaceCodec2, 0, CODECGAIN_AMBEPLUS);
CVocodecChannel *ChannelB = new CVocodecChannel(InterfaceAmbePlus, ChannelAmbePlus, InterfaceAmbe, ChannelAmbe, InterfaceCodec2, 0, CODECGAIN_AMBE2PLUS);
CVocodecChannel *ChannelC = new CVocodecChannel(InterfaceCodec2, 0, InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, CODECGAIN_CODEC2);
CVocodecChannel *ChannelD = new CVocodecChannel(InterfaceCodec2, 1, InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, CODECGAIN_CODEC2);
ChannelA->AddGroupChannel(ChannelB);
ChannelA->AddGroupChannel(ChannelC);
ChannelA->AddGroupChannel(ChannelD);
ChannelB->AddGroupChannel(ChannelA);
ChannelB->AddGroupChannel(ChannelC);
ChannelB->AddGroupChannel(ChannelD);
ChannelC->AddGroupChannel(ChannelA);
ChannelC->AddGroupChannel(ChannelB);
ChannelC->AddGroupChannel(ChannelD);
ChannelD->AddGroupChannel(ChannelA);
ChannelD->AddGroupChannel(ChannelB);
ChannelD->AddGroupChannel(ChannelC);
channels->push_back(ChannelA);
channels->push_back(ChannelB);
channels->push_back(ChannelC);
channels->push_back(ChannelD);
}
////////////////////////////////////////////////////////////////////////////////////////
@ -251,12 +261,12 @@ int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vector<CVocode
Codec2E->Init() && Codec2F->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
CreateChannelGroup(Usb3003C, 0, Usb3003C, 1, Codec2D, 0, channels);
CreateChannelGroup(Usb3003D, 0, Usb3003D, 1, Codec2E, 0, channels);
CreateChannelGroup(Usb3003C, 2, Usb3003D, 2, Codec2F, 0, channels);
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, channels);
CreateChannelGroup(Usb3003C, 0, Usb3003C, 1, Codec2D, channels);
CreateChannelGroup(Usb3003D, 0, Usb3003D, 1, Codec2E, channels);
CreateChannelGroup(Usb3003C, 2, Usb3003D, 2, Codec2F, channels);
// done
nStreams = 18;
}
@ -306,9 +316,9 @@ int CFtdiDeviceDescr::CreateUsb3006(CFtdiDeviceDescr *descr, std::vector<CVocode
Codec2A->Init() && Codec2B->Init() && Codec2C->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, channels);
// done
nStreams = 9;
}
@ -351,7 +361,7 @@ int CFtdiDeviceDescr::CreateUsb3003(CFtdiDeviceDescr *descr, std::vector<CVocode
if ( (Usb3003 != NULL) && Usb3003->Init(CODEC_NONE) && Codec2->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003, 0, Usb3003, 1, Codec2, 0, channels);
CreateChannelGroup(Usb3003, 0, Usb3003, 1, Codec2, channels);
// done
nStreams = 3;
}
@ -381,7 +391,7 @@ int CFtdiDeviceDescr::CreatePair(CUsb3000Interface *Usb3000A, CUsb3000Interface
if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) && Codec2->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3000A, 0, Usb3000B, 0, Codec2, 0, channels);
CreateChannelGroup(Usb3000A, 0, Usb3000B, 0, Codec2, channels);
// done
nStreams = 3;
}
@ -415,9 +425,9 @@ int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3003Interface
Codec2A->Init() && Codec2B->Init() && Codec2C->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, channels);
// done
nStreams = 9;
}
@ -451,8 +461,8 @@ int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3000Interface
Codec2A->Init() && Codec2B->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3000B, 0, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, channels);
CreateChannelGroup(Usb3003A, 2, Usb3000B, 0, Codec2B, channels);
// done
nStreams = 6;
}

@ -73,7 +73,7 @@ public:
protected:
// factory helper
static void CreateChannelGroup(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, int, std::vector<CVocodecChannel *>*);
static void CreateChannelGroup(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, std::vector<CVocodecChannel *>*);
static int CreateUsb3012(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateUsb3006(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);
static int CreateUsb3003(CFtdiDeviceDescr *, std::vector<CVocodecChannel *>*);

@ -64,10 +64,10 @@
// Codecs -------------------------------------------------------
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1
#define CODEC_AMBE2PLUS 2
#define CODEC_CODEC2 4
#define CODEC_ALL 7 // all available bits set
#define CODEC_AMBEPLUS 1 // DStar
#define CODEC_AMBE2PLUS 2 // DMR
#define CODEC_CODEC2_3200 4 // Codec 2 mode 3200
#define CODEC_CODEC2_2400 8 // Codec 2 mode 2400
// Transcoding speech gains
#define CODECGAIN_AMBEPLUS -10 // in dB

@ -221,7 +221,7 @@ CCodecStream *CTranscoder::GetStream(uint8 uiCodecIn)
if ( m_bConnected )
{
// yes, post openstream request
EncodeOpenstreamPacket(&Buffer, uiCodecIn, CODEC_ALL ^ uiCodecIn);
EncodeOpenstreamPacket(&Buffer, uiCodecIn, GetCodecsOut(uiCodecIn));
m_Socket.Send(Buffer, m_AmbedIp, TRANSCODER_PORT);
// wait relpy here
@ -232,7 +232,7 @@ CCodecStream *CTranscoder::GetStream(uint8 uiCodecIn)
std::cout << "ambed openstream(" << m_StreamidOpenStream << ") ok" << std::endl;
// create stream object
stream = new CCodecStream(m_StreamidOpenStream, uiCodecIn, CODEC_ALL ^ uiCodecIn);
stream = new CCodecStream(m_StreamidOpenStream, uiCodecIn, GetCodecsOut(uiCodecIn));
// init it
if ( stream->Init(m_PortOpenStream) )
@ -298,6 +298,20 @@ void CTranscoder::ReleaseStream(CCodecStream *stream)
}
}
////////////////////////////////////////////////////////////////////////////////////////
// codec helpers
uint8 CTranscoder::GetCodecsOut(uint8 CodecIn)
{
switch (CodecIn) {
case CODEC_AMBEPLUS: return CODEC_AMBE2PLUS | CODEC_CODEC2_3200;
case CODEC_AMBE2PLUS: return CODEC_AMBEPLUS | CODEC_CODEC2_3200;
case CODEC_CODEC2_3200:
case CODEC_CODEC2_2400: return CODEC_AMBEPLUS | CODEC_AMBE2PLUS;
default: return CODEC_NONE;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// keepalive helpers

@ -67,6 +67,9 @@ public:
void Task(void);
protected:
// codec helper
uint8 GetCodecsOut(uint8 CodecIn);
// keepalive helpers
void HandleKeepalives(void);

@ -66,7 +66,7 @@ int main(int argc, const char * argv[])
for ( int i = 0; i < nCodec2; i++ )
{
CTimePoint::TaskSleepFor(300);
Streams.push_back(g_Transcoder.GetStream(CODEC_CODEC2));
Streams.push_back(g_Transcoder.GetStream(CODEC_CODEC2_3200));
}
// and loop wait

@ -66,8 +66,8 @@
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1 // DStar
#define CODEC_AMBE2PLUS 2 // DMR
#define CODEC_CODEC2 4 // Codec 2
#define CODEC_ALL 7 // all available bits set
#define CODEC_CODEC2_3200 4 // Codec 2 mode 3200
#define CODEC_CODEC2_2400 8 // Codec 2 mode 2400

@ -73,7 +73,7 @@ bool CDextraOpenProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CB
uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
struct dstar_header DstarHeader;
Packet.ConvertToDstarStruct(&DstarHeader, CODEC_CODEC2);
Packet.ConvertToDstarStruct(&DstarHeader, CODEC_CODEC2_3200);
Buffer->Set(tag, sizeof(tag));
Buffer->Append(Packet.GetStreamId());

@ -108,7 +108,8 @@ const uint8 *CDvFramePacket::GetAmbe(uint8 uiCodec) const
{
case CODEC_AMBEPLUS: return m_uiAmbe;
case CODEC_AMBE2PLUS: return m_uiAmbePlus;
case CODEC_CODEC2: return m_uiCodec2;
case CODEC_CODEC2_3200:
case CODEC_CODEC2_2400: return m_uiCodec2;
default: return NULL;
}
}
@ -131,7 +132,8 @@ void CDvFramePacket::SetAmbe(uint8 uiCodec, uint8 *Ambe)
case CODEC_AMBE2PLUS:
::memcpy(m_uiAmbePlus, Ambe, sizeof(m_uiAmbePlus));
break;
case CODEC_CODEC2:
case CODEC_CODEC2_3200:
case CODEC_CODEC2_2400:
::memcpy(m_uiCodec2, Ambe, sizeof(m_uiCodec2));
break;
}
@ -147,7 +149,8 @@ void CDvFramePacket::ClearAmbe(uint8 uiCodec)
case CODEC_AMBE2PLUS:
::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus));
break;
case CODEC_CODEC2:
case CODEC_CODEC2_3200:
case CODEC_CODEC2_2400:
::memset(m_uiCodec2, 0, sizeof(m_uiCodec2));
break;
}

@ -102,13 +102,24 @@ void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer, uint8 Co
::memset(buffer, 0, sizeof(struct dstar_header));
buffer->Flag1 = m_uiFlag1;
buffer->Flag2 = m_uiFlag2;
buffer->Flag3 = (CodecOut == CODEC_AMBEPLUS) ? 0x00 : 0x01 ;
buffer->Flag3 = m_uiFlag3;
m_csUR.GetCallsign(buffer->UR);
m_csRPT1.GetCallsign(buffer->RPT1);
m_csRPT2.GetCallsign(buffer->RPT2);
m_csMY.GetCallsign(buffer->MY);
m_csMY.GetSuffix(buffer->SUFFIX);
buffer->Crc = m_uiCrc;
if ( CodecOut == CODEC_AMBEPLUS )
{
buffer->Flag3 = 0x00;
}
else if ( CodecOut == CODEC_CODEC2_3200 && m_uiFlag3 == 0x00 )
{
// If the codec is not set, it means the stream came from another
// protocol, so it should be transcoded into Codec 2 mode 3200.
buffer->Flag3 = 0x01;
}
}
@ -134,11 +145,14 @@ uint8 CDvHeaderPacket::GetCodec(void) const
{
// The D-STAR vocoder extension by SV9OAN uses Flag 3 of the header
// to identify whether the voice data payload is in Codec 2 format.
// Two Codec 2 modes are allowed (3200 or 2400) and optional FEC.
// Only support 3200 mode and no FEC here.
// Two Codec 2 modes are allowed, either 3200, or 2400 with added FEC.
if ( m_uiFlag3 == 0x01 )
{
return CODEC_CODEC2;
return CODEC_CODEC2_3200;
}
if ( m_uiFlag3 == 0x03 )
{
return CODEC_CODEC2_2400;
}
return CODEC_AMBEPLUS;

@ -141,9 +141,10 @@ void CProtocol::OnDvFramePacketIn(CDvFramePacket *Frame, const CIp *Ip)
if ( stream != NULL )
{
// place the voice data in the appropriate place
if ( stream->GetCodec() == CODEC_CODEC2 )
if ( stream->GetCodec() == CODEC_CODEC2_3200 ||
stream->GetCodec() == CODEC_CODEC2_2400 )
{
Frame->SetAmbe(CODEC_CODEC2, (uint8 *)Frame->GetAmbe());
Frame->SetAmbe(stream->GetCodec(), (uint8 *)Frame->GetAmbe());
Frame->ClearAmbe(CODEC_AMBEPLUS);
}
@ -162,9 +163,10 @@ void CProtocol::OnDvLastFramePacketIn(CDvLastFramePacket *Frame, const CIp *Ip)
if ( stream != NULL )
{
// place the voice data in the appropriate place
if ( stream->GetCodec() == CODEC_CODEC2 )
if ( stream->GetCodec() == CODEC_CODEC2_3200 ||
stream->GetCodec() == CODEC_CODEC2_2400 )
{
Frame->SetAmbe(CODEC_CODEC2, (uint8 *)Frame->GetAmbe());
Frame->SetAmbe(stream->GetCodec(), (uint8 *)Frame->GetAmbe());
Frame->ClearAmbe(CODEC_AMBEPLUS);
}

@ -215,7 +215,7 @@ CCodecStream *CTranscoder::GetStream(CPacketStream *PacketStream, uint8 uiCodecI
if ( m_bConnected )
{
// yes, post openstream request
EncodeOpenstreamPacket(&Buffer, uiCodecIn, CODEC_ALL ^ uiCodecIn);
EncodeOpenstreamPacket(&Buffer, uiCodecIn, GetCodecsOut(uiCodecIn));
m_Socket.Send(Buffer, m_Ip, TRANSCODER_PORT);
// wait relpy here
@ -226,7 +226,7 @@ CCodecStream *CTranscoder::GetStream(CPacketStream *PacketStream, uint8 uiCodecI
std::cout << "ambed openstream ok" << std::endl;
// create stream object
stream = new CCodecStream(PacketStream, m_StreamidOpenStream, uiCodecIn, CODEC_ALL ^ uiCodecIn);
stream = new CCodecStream(PacketStream, m_StreamidOpenStream, uiCodecIn, GetCodecsOut(uiCodecIn));
// init it
if ( stream->Init(m_PortOpenStream) )
@ -311,6 +311,20 @@ void CTranscoder::ReleaseStream(CCodecStream *stream)
}
}
////////////////////////////////////////////////////////////////////////////////////////
// codec helpers
uint8 CTranscoder::GetCodecsOut(uint8 CodecIn)
{
switch (CodecIn) {
case CODEC_AMBEPLUS: return CODEC_AMBE2PLUS | CODEC_CODEC2_3200;
case CODEC_AMBE2PLUS: return CODEC_AMBEPLUS | CODEC_CODEC2_3200;
case CODEC_CODEC2_3200:
case CODEC_CODEC2_2400: return CODEC_AMBEPLUS | CODEC_AMBE2PLUS;
default: return CODEC_NONE;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// keepalive helpers

@ -67,6 +67,9 @@ public:
void Task(void);
protected:
// codec helper
uint8 GetCodecsOut(uint8 CodecIn);
// keepalive helpers
void HandleKeepalives(void);

@ -127,8 +127,8 @@
#define CODEC_NONE 0
#define CODEC_AMBEPLUS 1 // DStar
#define CODEC_AMBE2PLUS 2 // DMR
#define CODEC_CODEC2 4 // Codec 2
#define CODEC_ALL 7 // all available bits set
#define CODEC_CODEC2_3200 4 // Codec 2 mode 3200
#define CODEC_CODEC2_2400 8 // Codec 2 mode 2400
// DMRid database -----------------------------------------------

Loading…
Cancel
Save

Powered by TurnKey Linux.