From 635335eabbe4448f1acb3e49a1e8cb04556f87d8 Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Fri, 5 Apr 2019 23:28:35 +0300 Subject: [PATCH] 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. --- ambed/ccodec2interface.cpp | 79 ++++++++++++++++++++++++++++++------- ambed/ccodec2interface.h | 11 +++--- ambed/ccontroller.cpp | 9 +++-- ambed/cftdidevicedescr.cpp | 50 +++++++++++++---------- ambed/cftdidevicedescr.h | 2 +- ambed/main.h | 10 ++--- ambedtest/ctranscoder.cpp | 18 ++++++++- ambedtest/ctranscoder.h | 3 ++ ambedtest/main.cpp | 2 +- ambedtest/main.h | 4 +- src/cdextraopenprotocol.cpp | 2 +- src/cdvframepacket.cpp | 9 +++-- src/cdvheaderpacket.cpp | 22 +++++++++-- src/cprotocol.cpp | 10 +++-- src/ctranscoder.cpp | 18 ++++++++- src/ctranscoder.h | 3 ++ src/main.h | 4 +- 17 files changed, 187 insertions(+), 69 deletions(-) diff --git a/ambed/ccodec2interface.cpp b/ambed/ccodec2interface.cpp index 2494139..45a9c23 100644 --- a/ambed/ccodec2interface.cpp +++ b/ambed/ccodec2interface.cpp @@ -29,6 +29,7 @@ #include "cvoicepacket.h" #include "ccodec2interface.h" #include "cvocodecchannel.h" +#include //////////////////////////////////////////////////////////////////////////////////////// @@ -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); } diff --git a/ambed/ccodec2interface.h b/ambed/ccodec2interface.h index d71b3f8..9d217a7 100644 --- a/ambed/ccodec2interface.h +++ b/ambed/ccodec2interface.h @@ -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; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/ambed/ccontroller.cpp b/ambed/ccontroller.cpp index ba3d882..909e799 100644 --- a/ambed/ccontroller.cpp +++ b/ambed/ccontroller.cpp @@ -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))); } diff --git a/ambed/cftdidevicedescr.cpp b/ambed/cftdidevicedescr.cpp index ddca36e..1198d0b 100644 --- a/ambed/cftdidevicedescr.cpp +++ b/ambed/cftdidevicedescr.cpp @@ -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*channels) +void CFtdiDeviceDescr::CreateChannelGroup(CVocodecInterface *InterfaceAmbe, int ChannelAmbe, CVocodecInterface *InterfaceAmbePlus, int ChannelAmbePlus, CVocodecInterface *InterfaceCodec2, std::vector*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); + // 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::vectorInit() && 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::vectorInit() && 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::vectorInit(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; } diff --git a/ambed/cftdidevicedescr.h b/ambed/cftdidevicedescr.h index 330bb33..6909abb 100644 --- a/ambed/cftdidevicedescr.h +++ b/ambed/cftdidevicedescr.h @@ -73,7 +73,7 @@ public: protected: // factory helper - static void CreateChannelGroup(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, int, std::vector*); + static void CreateChannelGroup(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, std::vector*); static int CreateUsb3012(CFtdiDeviceDescr *, std::vector*); static int CreateUsb3006(CFtdiDeviceDescr *, std::vector*); static int CreateUsb3003(CFtdiDeviceDescr *, std::vector*); diff --git a/ambed/main.h b/ambed/main.h index 0ee02b5..82e1273 100644 --- a/ambed/main.h +++ b/ambed/main.h @@ -63,11 +63,11 @@ #define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds // 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_NONE 0 +#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 diff --git a/ambedtest/ctranscoder.cpp b/ambedtest/ctranscoder.cpp index 8f00646..cec4ab2 100644 --- a/ambedtest/ctranscoder.cpp +++ b/ambedtest/ctranscoder.cpp @@ -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 diff --git a/ambedtest/ctranscoder.h b/ambedtest/ctranscoder.h index 2df670d..0f26bd4 100644 --- a/ambedtest/ctranscoder.h +++ b/ambedtest/ctranscoder.h @@ -67,6 +67,9 @@ public: void Task(void); protected: + // codec helper + uint8 GetCodecsOut(uint8 CodecIn); + // keepalive helpers void HandleKeepalives(void); diff --git a/ambedtest/main.cpp b/ambedtest/main.cpp index 5893830..ace9649 100644 --- a/ambedtest/main.cpp +++ b/ambedtest/main.cpp @@ -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 diff --git a/ambedtest/main.h b/ambedtest/main.h index a95a08d..b7500d2 100644 --- a/ambedtest/main.h +++ b/ambedtest/main.h @@ -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 diff --git a/src/cdextraopenprotocol.cpp b/src/cdextraopenprotocol.cpp index 59e1353..1e75de1 100644 --- a/src/cdextraopenprotocol.cpp +++ b/src/cdextraopenprotocol.cpp @@ -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()); diff --git a/src/cdvframepacket.cpp b/src/cdvframepacket.cpp index fa31007..1f527e7 100644 --- a/src/cdvframepacket.cpp +++ b/src/cdvframepacket.cpp @@ -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; } diff --git a/src/cdvheaderpacket.cpp b/src/cdvheaderpacket.cpp index 161df32..1345a89 100644 --- a/src/cdvheaderpacket.cpp +++ b/src/cdvheaderpacket.cpp @@ -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; diff --git a/src/cprotocol.cpp b/src/cprotocol.cpp index 673a971..8774f5f 100644 --- a/src/cprotocol.cpp +++ b/src/cprotocol.cpp @@ -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); } diff --git a/src/ctranscoder.cpp b/src/ctranscoder.cpp index 5b96e08..66cfd29 100644 --- a/src/ctranscoder.cpp +++ b/src/ctranscoder.cpp @@ -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 diff --git a/src/ctranscoder.h b/src/ctranscoder.h index 7d54c58..d401cbc 100644 --- a/src/ctranscoder.h +++ b/src/ctranscoder.h @@ -67,6 +67,9 @@ public: void Task(void); protected: + // codec helper + uint8 GetCodecsOut(uint8 CodecIn); + // keepalive helpers void HandleKeepalives(void); diff --git a/src/main.h b/src/main.h index 3c3d22a..ff77c82 100644 --- a/src/main.h +++ b/src/main.h @@ -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 -----------------------------------------------