diff --git a/ambed/ccodec2interface.cpp b/ambed/ccodec2interface.cpp new file mode 100644 index 0000000..2494139 --- /dev/null +++ b/ambed/ccodec2interface.cpp @@ -0,0 +1,242 @@ +// +// ccodec2interface.cpp +// ambed +// +// Created by Antony Chazapis (SV9OAN) on 26/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of ambed. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include +#include "ctimepoint.h" +#include "cambepacket.h" +#include "cvoicepacket.h" +#include "ccodec2interface.h" +#include "cvocodecchannel.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructor + +CCodec2Interface::CCodec2Interface() +: CVocodecInterface() +{} + +//////////////////////////////////////////////////////////////////////////////////////// +// destructor + +CCodec2Interface::~CCodec2Interface() +{ + codec2_destroy(codec2_state); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// initialization + +bool CCodec2Interface::Init(void) +{ + bool ok = true; + + // create codec state + codec2_state = codec2_create(CODEC2_MODE_3200); + if (codec2_state == NULL) + { + ok = false; + } + + // base class + if ( ok ) + { + ok &= CVocodecInterface::Init(); + } + + // done + return ok; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// task + +void CCodec2Interface::Task(void) +{ + CPacketQueue *Queue; + CVocodecChannel *Channel; + CAmbePacket AmbePacket; + CVoicePacket VoicePacket; + bool done; + + // process the streams (channels) incoming queue + do + { + done = true; + for ( int i = 0; i < GetNbChannels(); i++ ) + { + // get active outgoing channel for interface channel + Channel = GetChannelWithChannelOut(i); + + // any packet in voice queue 1 ? + if ( Channel != NULL && Channel->IsInterfaceOut1(this) ) + { + CVoicePacket *Packet = NULL; + + Queue = Channel->GetVoiceQueue1(); + if ( !Queue->empty() ) + { + // get packet + Packet = (CVoicePacket *)Queue->front(); + Queue->pop(); + } + Channel->ReleaseVoiceQueue1(); + + if ( Packet != NULL ) + { + // this is second step of transcoding + // we just received from a decoded speech packet + // encode and cpush back to relevant channel outcoming queue + EncodeVoicePacket(Packet, &AmbePacket); + AmbePacket.SetPid(Packet->GetPid()); + delete Packet; + + CAmbePacket *clone = new CAmbePacket(AmbePacket); + + Queue = Channel->GetPacketQueueOut1(); + Queue->push(clone); + Channel->ReleasePacketQueueOut1(); + + // done + done = false; + } + } + + // any packet in voice queue 1 ? + if ( Channel != NULL && Channel->IsInterfaceOut2(this) ) + { + CVoicePacket *Packet = NULL; + + Queue = Channel->GetVoiceQueue2(); + if ( !Queue->empty() ) + { + // get packet + Packet = (CVoicePacket *)Queue->front(); + Queue->pop(); + } + Channel->ReleaseVoiceQueue2(); + + if ( Packet != NULL ) + { + // this is second step of transcoding + // we just received from a decoded speech packet + // encode and cpush back to relevant channel outcoming queue + EncodeVoicePacket(Packet, &AmbePacket); + AmbePacket.SetPid(Packet->GetPid()); + delete Packet; + + CAmbePacket *clone = new CAmbePacket(AmbePacket); + + Queue = Channel->GetPacketQueueOut2(); + Queue->push(clone); + Channel->ReleasePacketQueueOut2(); + + // done + done = false; + } + } + + // get active incoming channel for interface channel + Channel = GetChannelWithChannelIn(i); + + // any packet in ambe queue for us ? + if ( Channel != NULL && Channel->IsInterfaceIn(this) ) + { + CAmbePacket *Packet = NULL; + + Queue = Channel->GetPacketQueueIn(); + if ( !Queue->empty() ) + { + // get packet + Packet = (CAmbePacket *)Queue->front(); + Queue->pop(); + } + Channel->ReleasePacketQueueIn(); + + if ( Packet != NULL ) + { + // 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); + VoicePacket.SetPid(Packet->GetPid()); + delete Packet; + + CVoicePacket *clone1 = new CVoicePacket(VoicePacket); + clone1->ApplyGain(Channel->GetSpeechGain()); + CVoicePacket *clone2 = new CVoicePacket(*clone1); + + Queue = Channel->GetVoiceQueue1(); + Queue->push(clone1); + Channel->ReleaseVoiceQueue1(); + + Queue = Channel->GetVoiceQueue2(); + Queue->push(clone2); + Channel->ReleaseVoiceQueue2(); + + // done + done = false; + } + } + } + } while (!done); + + // and wait a bit + CTimePoint::TaskSleepFor(2); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// decoder helper + +void CCodec2Interface::DecodeAmbePacket(CAmbePacket *PacketIn, CVoicePacket *PacketOut) +{ + short voice[160]; + + codec2_decode(codec2_state, voice, (unsigned char *)PacketIn->GetAmbe()); + for ( int i = 0; i < 160; i++ ) + { + voice[i] = MAKEWORD(HIBYTE(voice[i]), LOBYTE(voice[i])); + } + PacketOut->SetVoice((uint8 *)voice, 160 * 2); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// encoder helpers + +void CCodec2Interface::EncodeVoicePacket(CVoicePacket *PacketIn, CAmbePacket *PacketOut) +{ + unsigned char ambe[AMBE_SIZE]; + short voice[160]; + + ::memcpy(voice, (short *)PacketIn->GetVoice(), 160 * 2); + for ( int i = 0; i < 160; i++ ) + { + voice[i] = MAKEWORD(HIBYTE(voice[i]), LOBYTE(voice[i])); + } + codec2_encode(codec2_state, ambe, voice); + ambe[8] = 0x00; + PacketOut->SetCodec(CODEC_CODEC2); + PacketOut->SetAmbe((uint8 *)ambe); +} diff --git a/ambed/ccodec2interface.h b/ambed/ccodec2interface.h new file mode 100644 index 0000000..d71b3f8 --- /dev/null +++ b/ambed/ccodec2interface.h @@ -0,0 +1,68 @@ +// +// ccodec2interface.h +// ambed +// +// Created by Antony Chazapis (SV9OAN) on 26/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of ambed. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef ccodec2interface_h +#define ccodec2interface_h + +#include "cvocodecinterface.h" +#include + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CCodec2Interface : public CVocodecInterface +{ +public: + // constructors + CCodec2Interface(); + + // destructor + virtual ~CCodec2Interface(); + + // initialization + bool Init(void); + + // get + const char *GetName(void) const { return "Codec 2"; } + + // manage channels + int GetNbChannels(void) const { return 1; } + uint8 GetChannelCodec(int) const { return CODEC_CODEC2; } + + // task + void Task(void); + +protected: + // decoder helper + void DecodeAmbePacket(CAmbePacket *, CVoicePacket *); + + // encoder helpers + void EncodeVoicePacket(CVoicePacket *, CAmbePacket *); + + // data + struct CODEC2 *codec2_state; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* ccodec2interface_h */ diff --git a/ambed/ccontroller.cpp b/ambed/ccontroller.cpp index d6039e8..ba3d882 100644 --- a/ambed/ccontroller.cpp +++ b/ambed/ccontroller.cpp @@ -124,7 +124,7 @@ void CController::Task(void) CIp Ip; CCallsign Callsign; uint8 CodecIn; - uint8 CodecOut; + uint8 CodecsOut; uint16 StreamId; CStream *Stream; @@ -132,12 +132,12 @@ void CController::Task(void) if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 ) { // crack packet - if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecOut) ) + if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecsOut) ) { std::cout << "Stream Open from " << Callsign << std::endl; // try create the stream - Stream = OpenStream(Callsign, Ip, CodecIn, CodecOut); + Stream = OpenStream(Callsign, Ip, CodecIn, CodecsOut); // send back details if ( Stream != NULL ) @@ -202,14 +202,14 @@ void CController::Task(void) //////////////////////////////////////////////////////////////////////////////////////// // streams management -CStream *CController::OpenStream(const CCallsign &Callsign, const CIp &Ip, uint8 CodecIn, uint8 CodecOut) +CStream *CController::OpenStream(const CCallsign &Callsign, const CIp &Ip, uint8 CodecIn, uint8 CodecsOut) { CStream *stream = NULL; // create a new stream m_uiLastStreamId = (m_uiLastStreamId + 1); m_uiLastStreamId = (m_uiLastStreamId == NB_MAX_STREAMS+1) ? 1 : m_uiLastStreamId; - stream = new CStream(m_uiLastStreamId, Callsign, Ip, CodecIn, CodecOut); + stream = new CStream(m_uiLastStreamId, Callsign, Ip, CodecIn, CodecsOut); if ( stream->Init(TRANSCODER_PORT+m_uiLastStreamId) ) { std::cout << "Opened stream " << m_uiLastStreamId << std::endl; @@ -293,7 +293,7 @@ bool CController::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *Calls return valid; } -bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Callsign, uint8 *CodecIn, uint8 *CodecOut) +bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Callsign, uint8 *CodecIn, uint8 *CodecsOut) { uint8 tag[] = { 'A','M','B','E','D','O','S' }; @@ -303,10 +303,10 @@ bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Call // get callsign here Callsign->SetCallsign(&(Buffer.data()[7]), 8); *CodecIn = Buffer.data()[15]; - *CodecOut = Buffer.data()[16]; + *CodecsOut = Buffer.data()[16]; // valid ? - valid = Callsign->IsValid() && IsValidCodecIn(*CodecIn) && IsValidCodecOut(*CodecOut); + valid = Callsign->IsValid() && IsValidCodecIn(*CodecIn) && IsValidCodecsOut(*CodecsOut); } return valid; } @@ -347,7 +347,7 @@ void CController::EncodeStreamDescrPacket(CBuffer *Buffer, const CStream &Stream // codecin Buffer->Append((uint8)Stream.GetCodecIn()); // codecout - Buffer->Append((uint8)Stream.GetCodecOut()); + Buffer->Append((uint8)Stream.GetCodecsOut()); } void CController::EncodeNoStreamAvailablePacket(CBuffer *Buffer) @@ -363,11 +363,13 @@ void CController::EncodeNoStreamAvailablePacket(CBuffer *Buffer) bool CController::IsValidCodecIn(uint8 codec) { - return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) ); + return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) || (codec == CODEC_CODEC2)); } -bool CController::IsValidCodecOut(uint8 codec) +bool CController::IsValidCodecsOut(uint8 codec) { - return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) ); + return ((codec == (CODEC_AMBEPLUS | CODEC_CODEC2)) || + (codec == (CODEC_AMBE2PLUS | CODEC_CODEC2)) || + (codec == (CODEC_AMBEPLUS | CODEC_AMBE2PLUS))); } diff --git a/ambed/ccontroller.h b/ambed/ccontroller.h index c39fb60..37b6fed 100644 --- a/ambed/ccontroller.h +++ b/ambed/ccontroller.h @@ -76,7 +76,7 @@ protected: // codec helpers bool IsValidCodecIn(uint8); - bool IsValidCodecOut(uint8); + bool IsValidCodecsOut(uint8); protected: // control socket diff --git a/ambed/cftdidevicedescr.cpp b/ambed/cftdidevicedescr.cpp index e17f4e8..ddca36e 100644 --- a/ambed/cftdidevicedescr.cpp +++ b/ambed/cftdidevicedescr.cpp @@ -28,6 +28,7 @@ #include "cusb3003interface.h" #include "cusb3003hrinterface.h" #include "cusb3003df2etinterface.h" +#include "ccodec2interface.h" #include "cftdidevicedescr.h" @@ -193,6 +194,25 @@ int CFtdiDeviceDescr::GetNbChannels(void) const return iNbChs; } +//////////////////////////////////////////////////////////////////////////////////////// +// factory helper + +void CFtdiDeviceDescr::CreateChannelGroup(CVocodecInterface *InterfaceAmbe, int ChannelAmbe, CVocodecInterface *InterfaceAmbePlus, int ChannelAmbePlus, CVocodecInterface *InterfaceCodec2, int ChannelCodec2, 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); + ChannelA->AddGroupChannel(ChannelB); + ChannelA->AddGroupChannel(ChannelC); + ChannelB->AddGroupChannel(ChannelA); + ChannelB->AddGroupChannel(ChannelC); + ChannelC->AddGroupChannel(ChannelA); + ChannelC->AddGroupChannel(ChannelB); + channels->push_back(ChannelA); + channels->push_back(ChannelB); + channels->push_back(ChannelC); +} + //////////////////////////////////////////////////////////////////////////////////////// // DVSI's USB-3012 factory helper // @@ -214,69 +234,31 @@ int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vectorGetVid(), descr->GetPid(), descr->GetChannelDescription(2), descr->GetChannelSerialNumber(2)); CUsb3003HRInterface *Usb3003D = new CUsb3003HRInterface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(3), descr->GetChannelSerialNumber(3)); - + + // create the virtual interfaces for Codec 2 + CCodec2Interface *Codec2A = new CCodec2Interface(); + CCodec2Interface *Codec2B = new CCodec2Interface(); + CCodec2Interface *Codec2C = new CCodec2Interface(); + CCodec2Interface *Codec2D = new CCodec2Interface(); + CCodec2Interface *Codec2E = new CCodec2Interface(); + CCodec2Interface *Codec2F = new CCodec2Interface(); + // init the interfaces if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) && - Usb3003C->Init(CODEC_AMBEPLUS) && Usb3003D->Init(CODEC_AMBE2PLUS) ) + Usb3003C->Init(CODEC_AMBEPLUS) && Usb3003D->Init(CODEC_AMBE2PLUS) && + Codec2A->Init() && Codec2B->Init() && + Codec2C->Init() && Codec2D->Init() && + Codec2E->Init() && Codec2F->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch3 - Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch4 - Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch5 - Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - // ch6 - Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - // ch7 - Channel = new CVocodecChannel(Usb3003C, 0, Usb3003C, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003C->AddChannel(Channel); - // ch8 - Channel = new CVocodecChannel(Usb3003C, 1, Usb3003C, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003C->AddChannel(Channel); - // ch9 - Channel = new CVocodecChannel(Usb3003D, 0, Usb3003D, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003D->AddChannel(Channel); - // ch10 - Channel = new CVocodecChannel(Usb3003D, 1, Usb3003D, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003D->AddChannel(Channel); - // ch11 - Channel = new CVocodecChannel(Usb3003C, 2, Usb3003D, 2, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003C->AddChannel(Channel); - Usb3003D->AddChannel(Channel); - // ch12 - Channel = new CVocodecChannel(Usb3003D, 2, Usb3003C, 2, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003C->AddChannel(Channel); - Usb3003D->AddChannel(Channel); - //done - nStreams = 12; - } + // 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); + // done + nStreams = 18; } else { @@ -285,6 +267,12 @@ int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vectorGetVid(), descr->GetPid(), descr->GetChannelDescription(0), descr->GetChannelSerialNumber(0)); CUsb3003Interface *Usb3003B = new CUsb3003Interface(descr->GetVid(), descr->GetPid(), descr->GetChannelDescription(1), descr->GetChannelSerialNumber(1)); - + + // create the virtual interfaces for Codec 2 + CCodec2Interface *Codec2A = new CCodec2Interface(); + CCodec2Interface *Codec2B = new CCodec2Interface(); + CCodec2Interface *Codec2C = new CCodec2Interface(); + // init the interfaces - if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) ) + if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) && + Codec2A->Init() && Codec2B->Init() && Codec2C->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch3 - Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch4 - Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch5 - Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - // ch6 - Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - //done - nStreams = 6; - } + // 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); + // done + nStreams = 9; } else { // cleanup delete Usb3003A; delete Usb3003B; + delete Codec2A; + delete Codec2B; + delete Codec2C; } // done @@ -372,29 +343,23 @@ int CFtdiDeviceDescr::CreateUsb3003(CFtdiDeviceDescr *descr, std::vectorInit(CODEC_NONE) ) + if ( (Usb3003 != NULL) && Usb3003->Init(CODEC_NONE) && Codec2->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3003, 0, Usb3003, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3003, 1, Usb3003, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003->AddChannel(Channel); - // done - nStreams = 2; - } + // create the channels in groups + CreateChannelGroup(Usb3003, 0, Usb3003, 1, Codec2, 0, channels); + // done + nStreams = 3; } else { // cleanup delete Usb3003; + delete Codec2; } // done @@ -408,32 +373,24 @@ int CFtdiDeviceDescr::CreateUsb3003(CFtdiDeviceDescr *descr, std::vector*channels) { int nStreams = 0; - + + // create the virtual interfaces for Codec 2 + CCodec2Interface *Codec2 = new CCodec2Interface(); + // init the interfaces - if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) ) + if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) && Codec2->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3000A, 0, Usb3000B, 0, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3000A->AddChannel(Channel); - Usb3000B->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3000B, 0, Usb3000A, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3000A->AddChannel(Channel); - Usb3000B->AddChannel(Channel); - // done - nStreams = 2; - } + // create the channels in groups + CreateChannelGroup(Usb3000A, 0, Usb3000B, 0, Codec2, 0, channels); + // done + nStreams = 3; } else { // cleanup delete Usb3000A; delete Usb3000B; + delete Codec2; } // done @@ -447,48 +404,31 @@ int CFtdiDeviceDescr::CreatePair(CUsb3000Interface *Usb3000A, CUsb3000Interface int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3003Interface *Usb3003B, std::vector*channels) { int nStreams = 0; + + // create the virtual interfaces for Codec 2 + CCodec2Interface *Codec2A = new CCodec2Interface(); + CCodec2Interface *Codec2B = new CCodec2Interface(); + CCodec2Interface *Codec2C = new CCodec2Interface(); // init the interfaces - if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) ) + if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) && + Codec2A->Init() && Codec2B->Init() && Codec2C->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch3 - Channel = new CVocodecChannel(Usb3003B, 0, Usb3003B, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch4 - Channel = new CVocodecChannel(Usb3003B, 1, Usb3003B, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003B->AddChannel(Channel); - // ch5 - Channel = new CVocodecChannel(Usb3003A, 2, Usb3003B, 2, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - // ch6 - Channel = new CVocodecChannel(Usb3003B, 2, Usb3003A, 2, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3003B->AddChannel(Channel); - // done - nStreams = 6; - } + // 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); + // done + nStreams = 9; } else { // cleanup delete Usb3003A; delete Usb3003B; + delete Codec2A; + delete Codec2B; + delete Codec2C; } // done @@ -501,40 +441,28 @@ int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3003Interface int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3000Interface *Usb3000B, std::vector*channels) { int nStreams = 0; - + + // create the virtual interfaces for Codec 2 + CCodec2Interface *Codec2A = new CCodec2Interface(); + CCodec2Interface *Codec2B = new CCodec2Interface(); + // init the interfaces - if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) ) + if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) && + Codec2A->Init() && Codec2B->Init() ) { - CVocodecChannel *Channel; - // create all channels - { - // ch1 - Channel = new CVocodecChannel(Usb3003A, 0, Usb3003A, 1, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch2 - Channel = new CVocodecChannel(Usb3003A, 1, Usb3003A, 0, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - // ch3 - Channel = new CVocodecChannel(Usb3003A, 2, Usb3000B, 0, CODECGAIN_AMBEPLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3000B->AddChannel(Channel); - // ch4 - Channel = new CVocodecChannel(Usb3000B, 0, Usb3003A, 2, CODECGAIN_AMBE2PLUS); - channels->push_back(Channel); - Usb3003A->AddChannel(Channel); - Usb3000B->AddChannel(Channel); - // done - nStreams = 4; - } + // create the channels in groups + CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels); + CreateChannelGroup(Usb3003A, 2, Usb3000B, 0, Codec2B, 0, channels); + // done + nStreams = 6; } else { // cleanup delete Usb3003A; delete Usb3000B; + delete Codec2A; + delete Codec2B; } // done diff --git a/ambed/cftdidevicedescr.h b/ambed/cftdidevicedescr.h index 15fa362..330bb33 100644 --- a/ambed/cftdidevicedescr.h +++ b/ambed/cftdidevicedescr.h @@ -73,6 +73,7 @@ public: protected: // factory helper + static void CreateChannelGroup(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, int, std::vector*); static int CreateUsb3012(CFtdiDeviceDescr *, std::vector*); static int CreateUsb3006(CFtdiDeviceDescr *, std::vector*); static int CreateUsb3003(CFtdiDeviceDescr *, std::vector*); diff --git a/ambed/cstream.cpp b/ambed/cstream.cpp index feb3cac..dc25965 100644 --- a/ambed/cstream.cpp +++ b/ambed/cstream.cpp @@ -50,14 +50,14 @@ CStream::CStream() m_iLostPackets = 0; } -CStream::CStream(uint16 uiId, const CCallsign &Callsign, const CIp &Ip, uint8 uiCodecIn, uint8 uiCodecOut) +CStream::CStream(uint16 uiId, const CCallsign &Callsign, const CIp &Ip, uint8 uiCodecIn, uint8 uiCodecsOut) { m_uiId = uiId; m_Callsign = Callsign; m_Ip = Ip; m_uiPort = 0; m_uiCodecIn = uiCodecIn; - m_uiCodecOut = uiCodecOut; + m_uiCodecsOut = uiCodecsOut; m_bStopThread = false; m_pThread = NULL; m_VocodecChannel = NULL; @@ -84,6 +84,8 @@ CStream::~CStream() m_pThread->join(); delete m_pThread; } + + PurgeAllQueues(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -101,10 +103,12 @@ bool CStream::Init(uint16 uiPort) if ( ok ) { // open the vocodecchannel - ok &= ((m_VocodecChannel = g_Vocodecs.OpenChannel(m_uiCodecIn, m_uiCodecOut)) != NULL); + ok &= ((m_VocodecChannel = g_Vocodecs.OpenChannel(m_uiCodecIn, m_uiCodecsOut)) != NULL); if ( ok ) { + PurgeAllQueues(); + // store port m_uiPort = uiPort; @@ -149,6 +153,8 @@ void CStream::Close(void) m_pThread = NULL; } + PurgeAllQueues(); + // report std::cout << m_iLostPackets << " of " << m_iTotalPackets << " packets lost" << std::endl; } @@ -173,7 +179,8 @@ void CStream::Task(void) static CIp Ip; uint8 uiPid; uint8 Ambe[AMBE_FRAME_SIZE]; - CAmbePacket *packet; + CAmbePacket *packet1; + CAmbePacket *packet2; CPacketQueue *queue; // anything coming in from codec client ? @@ -187,27 +194,51 @@ void CStream::Task(void) m_iTotalPackets++; // post packet to VocoderChannel - packet = new CAmbePacket(uiPid, m_uiCodecIn, Ambe); + packet1 = new CAmbePacket(uiPid, m_uiCodecIn, Ambe); queue = m_VocodecChannel->GetPacketQueueIn(); - queue->push(packet); + queue->push(packet1); m_VocodecChannel->ReleasePacketQueueIn(); } } // anything in our queue ? - queue = m_VocodecChannel->GetPacketQueueOut(); + queue = m_VocodecChannel->GetPacketQueueOut1(); + while ( !queue->empty() ) + { + // get the packet + packet1 = (CAmbePacket *)queue->front(); + queue->pop(); + // add it to the outgoing queue + m_QueuePacketOut1.push(packet1); + } + m_VocodecChannel->ReleasePacketQueueOut1(); + + queue = m_VocodecChannel->GetPacketQueueOut2(); while ( !queue->empty() ) { // get the packet - packet = (CAmbePacket *)queue->front(); + packet2 = (CAmbePacket *)queue->front(); queue->pop(); + // add it to the outgoing queue + m_QueuePacketOut2.push(packet2); + } + m_VocodecChannel->ReleasePacketQueueOut2(); + + while ( !m_QueuePacketOut1.empty() && !m_QueuePacketOut2.empty() ) + { + packet1 = (CAmbePacket *)m_QueuePacketOut1.front(); + m_QueuePacketOut1.pop(); + packet2 = (CAmbePacket *)m_QueuePacketOut2.front(); + m_QueuePacketOut2.pop(); // send it to client - EncodeDvFramePacket(&Buffer, packet->GetPid(), packet->GetAmbe()); - m_Socket.Send(Buffer, Ip, m_uiPort); + // TODO : + // when packet PIDs are preserverd, make sure that they match + EncodeDvFramePacket(&Buffer, packet1->GetPid(), packet1->GetCodec(), packet1->GetAmbe(), packet2->GetCodec(), packet2->GetAmbe()); + m_Socket.Send(Buffer, Ip); // and done - delete packet; + delete packet1; + delete packet2; } - m_VocodecChannel->ReleasePacketQueueOut(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -229,13 +260,24 @@ bool CStream::IsValidDvFramePacket(const CBuffer &Buffer, uint8 *pid, uint8 *amb } //////////////////////////////////////////////////////////////////////////////////////// -// packet encodeing helpers +// packet encoding helpers -void CStream::EncodeDvFramePacket(CBuffer *Buffer, uint8 Pid, uint8 *Ambe) +void CStream::EncodeDvFramePacket(CBuffer *Buffer, uint8 Pid, uint8 Codec1, uint8 *Ambe1, uint8 Codec2, uint8 *Ambe2) { Buffer->clear(); - Buffer->Append((uint8)GetCodecOut()); + Buffer->Append((uint8)Codec1); + Buffer->Append((uint8)Codec2); Buffer->Append((uint8)Pid); - Buffer->Append(Ambe, 9); + Buffer->Append(Ambe1, 9); + Buffer->Append(Ambe2, 9); +} + +//////////////////////////////////////////////////////////////////////////////////////// +// queues helpers + +void CStream::PurgeAllQueues(void) +{ + m_QueuePacketOut1.Purge(); + m_QueuePacketOut2.Purge(); } diff --git a/ambed/cstream.h b/ambed/cstream.h index 2abc0f9..7958c94 100644 --- a/ambed/cstream.h +++ b/ambed/cstream.h @@ -50,7 +50,7 @@ public: uint16 GetId(void) const { return m_uiId; } uint16 GetPort(void) const { return m_uiPort; } uint8 GetCodecIn(void) const { return m_uiCodecIn; } - uint8 GetCodecOut(void) const { return m_uiCodecOut; } + uint8 GetCodecsOut(void) const { return m_uiCodecsOut; } // activity timer bool IsActive(void) const { return m_LastActivity.DurationSinceNow() <= STREAM_ACTIVITY_TIMEOUT; } @@ -64,8 +64,10 @@ protected: bool IsValidDvFramePacket(const CBuffer &, uint8 *, uint8 *); // packet encodeing helpers - void EncodeDvFramePacket(CBuffer *, uint8, uint8 *); - + void EncodeDvFramePacket(CBuffer *, uint8, uint8, uint8 *, uint8, uint8 *); + + // queues helpers + void PurgeAllQueues(void); protected: // data @@ -73,7 +75,7 @@ protected: CUdpSocket m_Socket; uint16 m_uiPort; uint8 m_uiCodecIn; - uint8 m_uiCodecOut; + uint8 m_uiCodecsOut; CVocodecChannel *m_VocodecChannel; // client details @@ -91,6 +93,9 @@ protected: bool m_bStopThread; std::thread *m_pThread; + // outgoing packet queues + CPacketQueue m_QueuePacketOut1; + CPacketQueue m_QueuePacketOut2; }; //////////////////////////////////////////////////////////////////////////////////////// diff --git a/ambed/cusb3000interface.cpp b/ambed/cusb3000interface.cpp index b340cba..077a648 100644 --- a/ambed/cusb3000interface.cpp +++ b/ambed/cusb3000interface.cpp @@ -72,43 +72,6 @@ uint8 CUsb3000Interface::GetChannelCodec(int iCh) const return (iCh == 0) ? m_uiChCodec : CODEC_NONE; } -//////////////////////////////////////////////////////////////////////////////////////// -// manage vocodec channels - -CVocodecChannel *CUsb3000Interface::GetChannelWithChannelIn(int iCh) -{ - CVocodecChannel *Channel = NULL; - bool done = false; - for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) - { - if ( iCh == 0 ) - { - if ( (m_Channels[i]->GetChannelIn() == iCh) && !(m_Channels[i]->IsInterfaceOut(this)) ) - { - Channel = m_Channels[i]; - done = true; - } - } - } - return Channel; -} - -CVocodecChannel *CUsb3000Interface::GetChannelWithChannelOut(int iCh) -{ - CVocodecChannel *Channel = NULL; - bool done = false; - for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) - { - if ( (m_Channels[i]->GetChannelOut() == iCh) && (m_Channels[i]->IsInterfaceOut(this)) ) - { - Channel = m_Channels[i]; - done = true; - } - } - return Channel; -} - - //////////////////////////////////////////////////////////////////////////////////////// // decoder helper diff --git a/ambed/cusb3000interface.h b/ambed/cusb3000interface.h index 1968b7b..75acde6 100644 --- a/ambed/cusb3000interface.h +++ b/ambed/cusb3000interface.h @@ -54,10 +54,6 @@ public: int GetNbChannels(void) const { return USB3000_NB_CH; } uint8 GetChannelCodec(int) const; - // manage vocodec channels - CVocodecChannel *GetChannelWithChannelIn(int); - CVocodecChannel *GetChannelWithChannelOut(int); - protected: // decoder helper bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); diff --git a/ambed/cusb3003interface.cpp b/ambed/cusb3003interface.cpp index 471dc39..ec65ae6 100644 --- a/ambed/cusb3003interface.cpp +++ b/ambed/cusb3003interface.cpp @@ -81,50 +81,6 @@ uint8 CUsb3003Interface::GetChannelCodec(int iCh) const return uiCodec; } -//////////////////////////////////////////////////////////////////////////////////////// -// manage vocodec channels - -CVocodecChannel *CUsb3003Interface::GetChannelWithChannelIn(int iCh) -{ - CVocodecChannel *Channel = NULL; - bool done = false; - for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) - { - if ( iCh == 2 ) - { - if ( (m_Channels[i]->GetChannelIn() == iCh) && !(m_Channels[i]->IsInterfaceOut(this)) ) - { - Channel = m_Channels[i]; - done = true; - } - } - else - { - if ( (m_Channels[i]->GetChannelIn() == iCh) && (m_Channels[i]->IsInterfaceOut(this)) ) - { - Channel = m_Channels[i]; - done = true; - } - } - } - return Channel; -} - -CVocodecChannel *CUsb3003Interface::GetChannelWithChannelOut(int iCh) -{ - CVocodecChannel *Channel = NULL; - bool done = false; - for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) - { - if ( (m_Channels[i]->GetChannelOut() == iCh) && (m_Channels[i]->IsInterfaceOut(this)) ) - { - Channel = m_Channels[i]; - done = true; - } - } - return Channel; -} - //////////////////////////////////////////////////////////////////////////////////////// // decoder helper diff --git a/ambed/cusb3003interface.h b/ambed/cusb3003interface.h index 984130e..c10e214 100644 --- a/ambed/cusb3003interface.h +++ b/ambed/cusb3003interface.h @@ -53,10 +53,6 @@ public: int GetNbChannels(void) const { return USB3003_NB_CH; } uint8 GetChannelCodec(int) const; - // manage vocodec channels - CVocodecChannel *GetChannelWithChannelIn(int); - CVocodecChannel *GetChannelWithChannelOut(int); - protected: // decoder helper bool IsValidChannelPacket(const CBuffer &, int *, CAmbePacket *); diff --git a/ambed/cusb3xxxinterface.cpp b/ambed/cusb3xxxinterface.cpp index c8eb461..8c4fa0a 100644 --- a/ambed/cusb3xxxinterface.cpp +++ b/ambed/cusb3xxxinterface.cpp @@ -150,11 +150,17 @@ void CUsb3xxxInterface::Task(void) Channel = GetChannelWithChannelIn(iCh); if ( Channel != NULL ) { - Queue = Channel->GetVoiceQueue(); - CVoicePacket *clone = new CVoicePacket(VoicePacket); - clone->ApplyGain(Channel->GetSpeechGain()); - Queue->push(clone); - Channel->ReleaseVoiceQueue(); + CVoicePacket *clone1 = new CVoicePacket(VoicePacket); + clone1->ApplyGain(Channel->GetSpeechGain()); + CVoicePacket *clone2 = new CVoicePacket(*clone1); + + Queue = Channel->GetVoiceQueue1(); + Queue->push(clone1); + Channel->ReleaseVoiceQueue1(); + + Queue = Channel->GetVoiceQueue2(); + Queue->push(clone2); + Channel->ReleaseVoiceQueue2(); } } else if ( IsValidChannelPacket(Buffer, &iCh, &AmbePacket) ) @@ -170,10 +176,20 @@ void CUsb3xxxInterface::Task(void) Channel = GetChannelWithChannelOut(iCh); if ( Channel != NULL ) { - Queue = Channel->GetPacketQueueOut(); CAmbePacket *clone = new CAmbePacket(AmbePacket); - Queue->push(clone); - Channel->ReleasePacketQueueOut(); + + if ( Channel->IsInterfaceOut1(this) ) + { + Queue = Channel->GetPacketQueueOut1(); + Queue->push(clone); + Channel->ReleasePacketQueueOut1(); + } + else if ( Channel->IsInterfaceOut2(this) ) + { + Queue = Channel->GetPacketQueueOut2(); + Queue->push(clone); + Channel->ReleasePacketQueueOut2(); + } } } } @@ -184,15 +200,15 @@ void CUsb3xxxInterface::Task(void) do { done = true; - for ( int i = 0; i < m_Channels.size(); i++) + for ( int i = 0; i < GetNbChannels(); i++ ) { - // get channel - Channel = m_Channels[i]; + // get active outgoing channel for interface channel + Channel = GetChannelWithChannelOut(i); - // any packet in voice queue ? - if ( Channel->IsInterfaceOut(this) ) + // any packet in voice queue 1 ? + if ( Channel != NULL && Channel->IsInterfaceOut1(this) ) { - Queue = Channel->GetVoiceQueue(); + Queue = Channel->GetVoiceQueue1(); if ( !Queue->empty() ) { // get packet @@ -201,17 +217,41 @@ void CUsb3xxxInterface::Task(void) // this is second step of transcoding // we just received from hardware a decoded speech packet // post it to relevant channel encoder - int i = Channel->GetChannelOut(); + int i = Channel->GetChannelOut1(); Packet->SetChannel(i); m_SpeechQueues[i]->push(Packet); // done done = false; } - Channel->ReleaseVoiceQueue(); + Channel->ReleaseVoiceQueue1(); + } + + // any packet in voice queue 2 ? + if ( Channel != NULL && Channel->IsInterfaceOut2(this) ) + { + Queue = Channel->GetVoiceQueue2(); + if ( !Queue->empty() ) + { + // get packet + CVoicePacket *Packet = (CVoicePacket *)Queue->front(); + Queue->pop(); + // this is second step of transcoding + // we just received from hardware a decoded speech packet + // post it to relevant channel encoder + int i = Channel->GetChannelOut2(); + Packet->SetChannel(i); + m_SpeechQueues[i]->push(Packet); + // done + done = false; + } + Channel->ReleaseVoiceQueue2(); } + // get active incoming channel for interface channel + Channel = GetChannelWithChannelIn(i); + // any packet in ambe queue for us ? - if ( Channel->IsInterfaceIn(this) ) + if ( Channel != NULL && Channel->IsInterfaceIn(this) ) { Queue = Channel->GetPacketQueueIn(); if ( !Queue->empty() ) diff --git a/ambed/cvocodecchannel.cpp b/ambed/cvocodecchannel.cpp index 0212424..c02c1b1 100644 --- a/ambed/cvocodecchannel.cpp +++ b/ambed/cvocodecchannel.cpp @@ -31,13 +31,16 @@ //////////////////////////////////////////////////////////////////////////////////////// // constructor -CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVocodecInterface *InterfaceOut, int iChOut, int iSpeechGain) +CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVocodecInterface *InterfaceOut1, int iChOut1, CVocodecInterface *InterfaceOut2, int iChOut2, int iSpeechGain) { m_bOpen = false; + m_GroupChannels.reserve(2); m_InterfaceIn = InterfaceIn; m_iChannelIn = iChIn; - m_InterfaceOut = InterfaceOut; - m_iChannelOut = iChOut; + m_InterfaceOut1 = InterfaceOut1; + m_iChannelOut1 = iChOut1; + m_InterfaceOut2 = InterfaceOut2; + m_iChannelOut2 = iChOut2; m_iSpeechGain = iSpeechGain; } @@ -46,9 +49,41 @@ CVocodecChannel::CVocodecChannel(CVocodecInterface *InterfaceIn, int iChIn, CVoc CVocodecChannel::~CVocodecChannel() { + // empty array of grouped channels + // channels are deleted by their owner (CVocodecs) + m_GroupChannels.clear(); + PurgeAllQueues(); } +//////////////////////////////////////////////////////////////////////////////////////// +// manage group + +void CVocodecChannel::AddGroupChannel(CVocodecChannel *Channel) +{ + m_GroupChannels.push_back(Channel); +} + +bool CVocodecChannel::IsAvailable(void) const +{ + if ( m_bOpen ) + { + return false; + } + + bool available = true; + + for ( int i = 0; (i < m_GroupChannels.size()) && available; i++ ) + { + if ( m_GroupChannels[i]->m_bOpen ) + { + available = false; + } + } + + return available; +} + //////////////////////////////////////////////////////////////////////////////////////// // open & close @@ -60,9 +95,13 @@ bool CVocodecChannel::Open(void) m_bOpen = true; ok = true; PurgeAllQueues(); + m_InterfaceIn->SetChannelWithChannelIn(this, m_iChannelIn); + m_InterfaceOut1->SetChannelWithChannelOut(this, m_iChannelOut1); + m_InterfaceOut2->SetChannelWithChannelOut(this, m_iChannelOut2); std::cout << "Vocodec channel " << m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " << - m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " open" << std::endl; + m_InterfaceOut1->GetName() << ":" << (int)m_iChannelOut1 << ", " << + m_InterfaceOut2->GetName() << ":" << (int)m_iChannelOut2 << " open" << std::endl; } return ok; } @@ -73,9 +112,13 @@ void CVocodecChannel::Close(void) { m_bOpen = false; PurgeAllQueues(); + m_InterfaceIn->SetChannelWithChannelIn(NULL, m_iChannelIn); + m_InterfaceOut1->SetChannelWithChannelOut(NULL, m_iChannelOut1); + m_InterfaceOut2->SetChannelWithChannelOut(NULL, m_iChannelOut2); std::cout << "Vocodec channel " << - m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " << - m_InterfaceOut->GetName() << ":" << (int)m_iChannelOut << " closed" << std::endl; + m_InterfaceIn->GetName() << ":" << (int)m_iChannelIn << " -> " << + m_InterfaceOut1->GetName() << ":" << (int)m_iChannelOut1 << ", " << + m_InterfaceOut2->GetName() << ":" << (int)m_iChannelOut2 << " closed" << std::endl; } } @@ -87,9 +130,19 @@ uint8 CVocodecChannel::GetCodecIn(void) const return m_InterfaceIn->GetChannelCodec(m_iChannelIn); } -uint8 CVocodecChannel::GetCodecOut(void) const +uint8 CVocodecChannel::GetCodecOut1(void) const +{ + return m_InterfaceOut1->GetChannelCodec(m_iChannelOut1); +} + +uint8 CVocodecChannel::GetCodecOut2(void) const +{ + return m_InterfaceOut2->GetChannelCodec(m_iChannelOut2); +} + +uint8 CVocodecChannel::GetCodecsOut(void) const { - return m_InterfaceOut->GetChannelCodec(m_iChannelOut); + return GetCodecOut1() | GetCodecOut2(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -99,10 +152,14 @@ void CVocodecChannel::PurgeAllQueues(void) { GetPacketQueueIn()->Purge(); ReleasePacketQueueIn(); - GetPacketQueueOut()->Purge(); - ReleasePacketQueueOut(); - GetVoiceQueue()->Purge(); - ReleaseVoiceQueue(); + GetPacketQueueOut1()->Purge(); + ReleasePacketQueueOut1(); + GetPacketQueueOut2()->Purge(); + ReleasePacketQueueOut2(); + GetVoiceQueue1()->Purge(); + ReleaseVoiceQueue1(); + GetVoiceQueue2()->Purge(); + ReleaseVoiceQueue2(); } diff --git a/ambed/cvocodecchannel.h b/ambed/cvocodecchannel.h index 4848c87..82834fa 100644 --- a/ambed/cvocodecchannel.h +++ b/ambed/cvocodecchannel.h @@ -37,34 +37,45 @@ class CVocodecChannel { public: // constructors - CVocodecChannel(CVocodecInterface *, int, CVocodecInterface *, int, int); + CVocodecChannel(CVocodecInterface *, int, CVocodecInterface *, int, CVocodecInterface *, int, int); // destructor virtual ~CVocodecChannel(); + // manage group + void AddGroupChannel(CVocodecChannel *); + bool IsAvailable(void) const; + // open & close bool Open(void); - bool IsOpen(void) const { return m_bOpen; } void Close(void); // get uint8 GetCodecIn(void) const; - uint8 GetCodecOut(void) const; + uint8 GetCodecOut1(void) const; + uint8 GetCodecOut2(void) const; + uint8 GetCodecsOut(void) const; int GetChannelIn(void) const { return m_iChannelIn; } - int GetChannelOut(void) const { return m_iChannelOut; } + int GetChannelOut1(void) const { return m_iChannelOut1; } + int GetChannelOut2(void) const { return m_iChannelOut2; } int GetSpeechGain(void) const { return m_iSpeechGain; } // interfaces bool IsInterfaceIn(const CVocodecInterface *interface) { return (interface == m_InterfaceIn); } - bool IsInterfaceOut(const CVocodecInterface *interface) { return (interface == m_InterfaceOut); } - + bool IsInterfaceOut1(const CVocodecInterface *interface) { return (interface == m_InterfaceOut1); } + bool IsInterfaceOut2(const CVocodecInterface *interface) { return (interface == m_InterfaceOut2); } + // queues CPacketQueue *GetPacketQueueIn(void) { m_QueuePacketIn.Lock(); return &m_QueuePacketIn; } void ReleasePacketQueueIn(void) { m_QueuePacketIn.Unlock(); } - CPacketQueue *GetPacketQueueOut(void) { m_QueuePacketOut.Lock(); return &m_QueuePacketOut; } - void ReleasePacketQueueOut(void) { m_QueuePacketOut.Unlock(); } - CPacketQueue *GetVoiceQueue(void) { m_QueueVoice.Lock(); return &m_QueueVoice; } - void ReleaseVoiceQueue(void) { m_QueueVoice.Unlock(); } + CPacketQueue *GetPacketQueueOut1(void) { m_QueuePacketOut1.Lock(); return &m_QueuePacketOut1; } + void ReleasePacketQueueOut1(void) { m_QueuePacketOut1.Unlock(); } + CPacketQueue *GetPacketQueueOut2(void) { m_QueuePacketOut2.Lock(); return &m_QueuePacketOut2; } + void ReleasePacketQueueOut2(void) { m_QueuePacketOut2.Unlock(); } + CPacketQueue *GetVoiceQueue1(void) { m_QueueVoice1.Lock(); return &m_QueueVoice1; } + void ReleaseVoiceQueue1(void) { m_QueueVoice1.Unlock(); } + CPacketQueue *GetVoiceQueue2(void) { m_QueueVoice2.Lock(); return &m_QueueVoice2; } + void ReleaseVoiceQueue2(void) { m_QueueVoice2.Unlock(); } // operators //virtual bool operator ==(const CVocodecChannel &) const { return false; } @@ -75,22 +86,29 @@ protected: protected: // status - bool m_bOpen; + bool m_bOpen; + + // array of grouped channels + std::vector m_GroupChannels; // connected interfaces - CVocodecInterface *m_InterfaceIn; - int m_iChannelIn; - CVocodecInterface *m_InterfaceOut; - int m_iChannelOut; + CVocodecInterface *m_InterfaceIn; + int m_iChannelIn; + CVocodecInterface *m_InterfaceOut1; + int m_iChannelOut1; + CVocodecInterface *m_InterfaceOut2; + int m_iChannelOut2; // ambe queues - CPacketQueue m_QueuePacketIn; - CPacketQueue m_QueuePacketOut; - // voice queue - CPacketQueue m_QueueVoice; + CPacketQueue m_QueuePacketIn; + CPacketQueue m_QueuePacketOut1; + CPacketQueue m_QueuePacketOut2; + // voice queues + CPacketQueue m_QueueVoice1; + CPacketQueue m_QueueVoice2; // settings - int m_iSpeechGain; + int m_iSpeechGain; }; diff --git a/ambed/cvocodecinterface.cpp b/ambed/cvocodecinterface.cpp index e730e09..9984f18 100644 --- a/ambed/cvocodecinterface.cpp +++ b/ambed/cvocodecinterface.cpp @@ -33,7 +33,6 @@ CVocodecInterface::CVocodecInterface() { - m_Channels.reserve(5); m_bStopThread = false; m_pThread = NULL; } @@ -43,10 +42,6 @@ CVocodecInterface::CVocodecInterface() CVocodecInterface::~CVocodecInterface() { - // empty channel array - // chennels are deleted by their owner (CVocodecs) - m_Channels.clear(); - // stop thread m_bStopThread = true; if ( m_pThread != NULL ) @@ -61,6 +56,13 @@ CVocodecInterface::~CVocodecInterface() bool CVocodecInterface::Init(void) { + // no open channel state + for ( int i = 0; i < GetNbChannels(); i++ ) + { + m_ChannelIn.push_back(NULL); + m_ChannelOut.push_back(NULL); + } + // reset stop flag m_bStopThread = false; @@ -85,11 +87,39 @@ void CVocodecInterface::Thread(CVocodecInterface *This) //////////////////////////////////////////////////////////////////////////////////////// -// manage Channels +// manage open Channel state + +void CVocodecInterface::SetChannelWithChannelIn(CVocodecChannel *Channel, int iCh) +{ + m_MutexChannels.lock(); + m_ChannelIn[iCh] = Channel; + m_ChannelOut[iCh] = NULL; + m_MutexChannels.unlock(); +} + +void CVocodecInterface::SetChannelWithChannelOut(CVocodecChannel *Channel, int iCh) +{ + m_MutexChannels.lock(); + m_ChannelIn[iCh] = NULL; + m_ChannelOut[iCh] = Channel; + m_MutexChannels.unlock(); +} -void CVocodecInterface::AddChannel(CVocodecChannel *Channel) +CVocodecChannel *CVocodecInterface::GetChannelWithChannelIn(int iCh) { - m_Channels.push_back(Channel); + CVocodecChannel *Channel; + m_MutexChannels.lock(); + Channel = m_ChannelIn[iCh]; + m_MutexChannels.unlock(); + return Channel; } +CVocodecChannel *CVocodecInterface::GetChannelWithChannelOut(int iCh) +{ + CVocodecChannel *Channel; + m_MutexChannels.lock(); + Channel = m_ChannelOut[iCh]; + m_MutexChannels.unlock(); + return Channel; +} diff --git a/ambed/cvocodecinterface.h b/ambed/cvocodecinterface.h index 66f8fbb..011380b 100644 --- a/ambed/cvocodecinterface.h +++ b/ambed/cvocodecinterface.h @@ -50,9 +50,12 @@ public: // manage channels virtual int GetNbChannels(void) const { return 0; } virtual uint8 GetChannelCodec(int) const { return CODEC_NONE; } - void AddChannel(CVocodecChannel *); - virtual CVocodecChannel *GetChannelWithChannelIn(int) { return NULL; } - virtual CVocodecChannel *GetChannelWithChannelOut(int) { return NULL; } + + // manage open channel state + void SetChannelWithChannelIn(CVocodecChannel *, int); + void SetChannelWithChannelOut(CVocodecChannel *, int); + CVocodecChannel *GetChannelWithChannelIn(int); + CVocodecChannel *GetChannelWithChannelOut(int); // task static void Thread(CVocodecInterface *); @@ -62,9 +65,11 @@ public: virtual bool operator ==(const CVocodecInterface &) const { return false; } protected: - // array of channels - std::vector m_Channels; - + // open channel state + std::mutex m_MutexChannels; + std::vector m_ChannelIn; + std::vector m_ChannelOut; + // thread bool m_bStopThread; std::thread *m_pThread; diff --git a/ambed/cvocodecs.cpp b/ambed/cvocodecs.cpp index aa28707..f762a25 100644 --- a/ambed/cvocodecs.cpp +++ b/ambed/cvocodecs.cpp @@ -200,13 +200,14 @@ bool CVocodecs::Init(void) // done + iNbCh /= 3; if ( ok ) { - std::cout << "Codec interfaces initialized successfully : " << iNbCh << " channels available" << std::endl; + std::cout << "Codec interfaces initialized successfully : " << iNbCh << " channel group" << ( iNbCh > 1 ? "s" : "" ) << " available" << std::endl; } else { - std::cout << "At least one codec interfaces failed to initialize : " << iNbCh << " channels availables" << std::endl; + std::cout << "At least one codec interfaces failed to initialize : " << iNbCh << " channel group" << ( iNbCh > 1 ? "s" : "" ) << " available" << std::endl; } // done return ok; @@ -267,7 +268,7 @@ bool CVocodecs::DiscoverFtdiDevices(void) //////////////////////////////////////////////////////////////////////////////////////// // manage channels -CVocodecChannel *CVocodecs::OpenChannel(uint8 uiCodecIn, uint8 uiCodecOut) +CVocodecChannel *CVocodecs::OpenChannel(uint8 uiCodecIn, uint8 uiCodecsOut) { CVocodecChannel *Channel = NULL; bool done = false; @@ -276,9 +277,9 @@ CVocodecChannel *CVocodecs::OpenChannel(uint8 uiCodecIn, uint8 uiCodecOut) m_MutexChannels.lock(); for ( int i = 0; (i < m_Channels.size()) && !done; i++ ) { - if ( !m_Channels[i]->IsOpen() && - (m_Channels[i]->GetCodecIn() == uiCodecIn) && - (m_Channels[i]->GetCodecOut() == uiCodecOut) ) + if ( (m_Channels[i]->GetCodecIn() == uiCodecIn) && + (m_Channels[i]->GetCodecsOut() == uiCodecsOut) && + m_Channels[i]->IsAvailable() ) { if ( m_Channels[i]->Open() ) { @@ -295,5 +296,7 @@ CVocodecChannel *CVocodecs::OpenChannel(uint8 uiCodecIn, uint8 uiCodecOut) void CVocodecs::CloseChannel(CVocodecChannel *Channel) { + m_MutexChannels.lock(); Channel->Close(); + m_MutexChannels.unlock(); } diff --git a/ambed/cvoicepacket.cpp b/ambed/cvoicepacket.cpp index 0fc05f7..f8ea67c 100644 --- a/ambed/cvoicepacket.cpp +++ b/ambed/cvoicepacket.cpp @@ -75,6 +75,11 @@ void CVoicePacket::SetVoice(const uint8 *voice, int size) void CVoicePacket::ApplyGain(int dB) { + if ( dB == 0 ) + { + return; + } + float mult = pow(10, dB/20.0); for ( int i = 0; i < m_iSize; i += 2 ) { diff --git a/ambed/main.h b/ambed/main.h index a432f36..0ee02b5 100644 --- a/ambed/main.h +++ b/ambed/main.h @@ -47,9 +47,9 @@ // version ----------------------------------------------------- -#define VERSION_MAJOR 1 -#define VERSION_MINOR 3 -#define VERSION_REVISION 2 +#define VERSION_MAJOR 2 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 // global ------------------------------------------------------ @@ -66,10 +66,13 @@ #define CODEC_NONE 0 #define CODEC_AMBEPLUS 1 #define CODEC_AMBE2PLUS 2 +#define CODEC_CODEC2 4 +#define CODEC_ALL 7 // all available bits set // Transcoding speech gains -#define CODECGAIN_AMBEPLUS -10 // in dB +#define CODECGAIN_AMBEPLUS -10 // in dB #define CODECGAIN_AMBE2PLUS +10 // in dB +#define CODECGAIN_CODEC2 0 // in dB // Timeouts ----------------------------------------------------- #define STREAM_ACTIVITY_TIMEOUT 3 // in seconds diff --git a/ambed/makefile b/ambed/makefile index c556a28..0a853c5 100644 --- a/ambed/makefile +++ b/ambed/makefile @@ -8,7 +8,7 @@ EXECUTABLE=ambed all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) - $(CC) $(LDFLAGS) $(OBJECTS) -lftd2xx -Wl,-rpath,/usr/local/lib -o $@ + $(CC) $(LDFLAGS) $(OBJECTS) -lftd2xx -lcodec2 -Wl,-rpath,/usr/local/lib -o $@ .cpp.o: $(CC) $(CFLAGS) $< -o $@ diff --git a/ambedtest/ccodecstream.cpp b/ambedtest/ccodecstream.cpp index 5c5fcf3..b42a94d 100644 --- a/ambedtest/ccodecstream.cpp +++ b/ambedtest/ccodecstream.cpp @@ -34,14 +34,14 @@ //////////////////////////////////////////////////////////////////////////////////////// // constructor -CCodecStream::CCodecStream(uint16 uiId, uint8 uiCodecIn, uint8 uiCodecOut) +CCodecStream::CCodecStream(uint16 uiId, uint8 uiCodecIn, uint8 uiCodecsOut) { m_bStopThread = false; m_pThread = NULL; m_uiStreamId = uiId; m_uiPid = 0; m_uiCodecIn = uiCodecIn; - m_uiCodecOut = uiCodecOut; + m_uiCodecsOut = uiCodecsOut; m_bConnected = false; m_iAmbeSrcPtr = 0; m_iAmbeDestPtr = 0; @@ -166,7 +166,10 @@ void CCodecStream::Task(void) { CBuffer Buffer; CIp Ip; - uint8 Ambe[AMBE_SIZE]; + uint8 Codec1; + uint8 Codec2; + uint8 Ambe1[AMBE_SIZE]; + uint8 Ambe2[AMBE_SIZE]; // connected ? if ( m_bConnected ) @@ -208,7 +211,7 @@ void CCodecStream::Task(void) if ( m_Socket.Receive(&Buffer, &Ip, 1) != -1 ) { // crack - if ( IsValidAmbePacket(Buffer, Ambe) ) + if ( IsValidAmbePacket(Buffer, &Codec1, Ambe1, &Codec2, Ambe2) ) { m_TimeoutTimer.Now(); @@ -246,13 +249,16 @@ void CCodecStream::Task(void) //////////////////////////////////////////////////////////////////////////////////////// /// packet decoding helpers -bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Ambe) +bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Codec1, uint8 *Ambe1, uint8 *Codec2, uint8 *Ambe2) { bool valid = false; - if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) ) + if ( (Buffer.size() == 21) && ((Buffer.data()[0] | Buffer.data()[1]) == m_uiCodecsOut) ) { - ::memcpy(Ambe, &(Buffer.data()[2]), 9); + *Codec1 = Buffer.data()[0]; + ::memcpy(Ambe1, &(Buffer.data()[3]), 9); + *Codec2 = Buffer.data()[1]; + ::memcpy(Ambe2, &(Buffer.data()[12]), 9); valid = true; } return valid; @@ -299,7 +305,7 @@ void CCodecStream::DisplayStats(void) // displays char sz[256]; sprintf(sz, "Stream %d (%d->%d) : %u / %u / %u : %.1f fps", - m_uiStreamId, m_uiCodecIn, m_uiCodecOut, + m_uiStreamId, m_uiCodecIn, m_uiCodecsOut, uiSent, uiReceived, uiBad, fps); std::cout << sz << std::endl; } diff --git a/ambedtest/ccodecstream.h b/ambedtest/ccodecstream.h index 4619648..fdb54c9 100644 --- a/ambedtest/ccodecstream.h +++ b/ambedtest/ccodecstream.h @@ -66,7 +66,7 @@ public: protected: // packet decoding helpers - bool IsValidAmbePacket(const CBuffer &, uint8 *); + bool IsValidAmbePacket(const CBuffer &, uint8 *, uint8 *, uint8 *, uint8 *); // packet encoding helpers void EncodeAmbePacket(CBuffer *, const uint8 *); @@ -87,7 +87,7 @@ protected: uint16 m_uiPort; uint8 m_uiPid; uint8 m_uiCodecIn; - uint8 m_uiCodecOut; + uint8 m_uiCodecsOut; // socket CIp m_Ip; diff --git a/ambedtest/ctranscoder.cpp b/ambedtest/ctranscoder.cpp index 5d7805b..8f00646 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, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS); + EncodeOpenstreamPacket(&Buffer, uiCodecIn, CODEC_ALL ^ 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, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS); + stream = new CCodecStream(m_StreamidOpenStream, uiCodecIn, CODEC_ALL ^ uiCodecIn); // init it if ( stream->Init(m_PortOpenStream) ) @@ -368,14 +368,14 @@ void CTranscoder::EncodeKeepAlivePacket(CBuffer *Buffer) Buffer->Append((uint8 *)(const char *)"XLX000 ", 8); } -void CTranscoder::EncodeOpenstreamPacket(CBuffer *Buffer, uint8 uiCodecIn, uint8 uiCodecOut) +void CTranscoder::EncodeOpenstreamPacket(CBuffer *Buffer, uint8 uiCodecIn, uint8 uiCodecsOut) { uint8 tag[] = { 'A','M','B','E','D','O','S' }; Buffer->Set(tag, sizeof(tag)); Buffer->Append((uint8 *)(const char *)"XLX000 ", 8); Buffer->Append((uint8)uiCodecIn); - Buffer->Append((uint8)uiCodecOut); + Buffer->Append((uint8)uiCodecsOut); } void CTranscoder::EncodeClosestreamPacket(CBuffer *Buffer, uint16 uiStreamId) diff --git a/ambedtest/main.cpp b/ambedtest/main.cpp index c0d975a..5893830 100644 --- a/ambedtest/main.cpp +++ b/ambedtest/main.cpp @@ -32,10 +32,10 @@ int main(int argc, const char * argv[]) std::vector Streams; // check args - if ( argc != 5 ) + if ( argc != 6 ) { - std::cout << "Usage: ambedtest myip ambedip nbdmrstreams nbdstarstreams" << std::endl; - std::cout << "example: ambed 192.168.178.212 127.0.0.1 2 2" << std::endl; + std::cout << "Usage: ambedtest myip ambedip nbdmrstreams nbdstarstreams nbcodec2streams" << std::endl; + std::cout << "example: ambed 192.168.178.212 127.0.0.1 2 2 2" << std::endl; return 1; } @@ -49,6 +49,7 @@ int main(int argc, const char * argv[]) // create streams int nDmr = atoi(argv[3]); int nDstar = atoi(argv[4]); + int nCodec2 = atoi(argv[5]); for ( int i = 0; i < nDmr; i++ ) { @@ -61,6 +62,12 @@ int main(int argc, const char * argv[]) CTimePoint::TaskSleepFor(300); Streams.push_back(g_Transcoder.GetStream(CODEC_AMBEPLUS)); } + + for ( int i = 0; i < nCodec2; i++ ) + { + CTimePoint::TaskSleepFor(300); + Streams.push_back(g_Transcoder.GetStream(CODEC_CODEC2)); + } // and loop wait std::cin.get(); diff --git a/ambedtest/main.h b/ambedtest/main.h index b6bc7ed..a95a08d 100644 --- a/ambedtest/main.h +++ b/ambedtest/main.h @@ -47,7 +47,7 @@ // version ----------------------------------------------------- -#define VERSION_MAJOR 1 +#define VERSION_MAJOR 2 #define VERSION_MINOR 0 #define VERSION_REVISION 0 @@ -66,6 +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 diff --git a/src/cbmclient.h b/src/cbmclient.h index fc47778..7ec6545 100644 --- a/src/cbmclient.h +++ b/src/cbmclient.h @@ -51,7 +51,6 @@ public: int GetProtocol(void) const { return PROTOCOL_XLX; } int GetProtocolRevision(void) const { return XLX_PROTOCOL_REVISION_2; } const char *GetProtocolName(void) const { return "XLX"; } - int GetCodec(void) const { return CODEC_AMBE2PLUS; } bool IsPeer(void) const { return true; } // status diff --git a/src/cclient.h b/src/cclient.h index 3fa2590..8639d9f 100644 --- a/src/cclient.h +++ b/src/cclient.h @@ -65,7 +65,6 @@ public: // identity virtual int GetProtocol(void) const { return PROTOCOL_NONE; } virtual int GetProtocolRevision(void) const { return 0; } - virtual int GetCodec(void) const { return CODEC_NONE; } virtual const char *GetProtocolName(void) const { return "none"; } virtual bool IsNode(void) const { return false; } virtual bool IsPeer(void) const { return false; } diff --git a/src/ccodecstream.cpp b/src/ccodecstream.cpp index 7d8e0c8..c407fa2 100644 --- a/src/ccodecstream.cpp +++ b/src/ccodecstream.cpp @@ -36,14 +36,14 @@ //////////////////////////////////////////////////////////////////////////////////////// // constructor -CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16 uiId, uint8 uiCodecIn, uint8 uiCodecOut) +CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16 uiId, uint8 uiCodecIn, uint8 uiCodecsOut) { m_bStopThread = false; m_pThread = NULL; m_uiStreamId = uiId; m_uiPid = 0; m_uiCodecIn = uiCodecIn; - m_uiCodecOut = uiCodecOut; + m_uiCodecsOut = uiCodecsOut; m_bConnected = false; m_fPingMin = -1; m_fPingMax = -1; @@ -155,14 +155,17 @@ void CCodecStream::Task(void) { CBuffer Buffer; CIp Ip; - uint8 Ambe[AMBE_SIZE]; + uint8 Codec1; + uint8 Codec2; + uint8 Ambe1[AMBE_SIZE]; + uint8 Ambe2[AMBE_SIZE]; uint8 DStarSync[] = { 0x55,0x2D,0x16 }; // any packet from transcoder if ( m_Socket.Receive(&Buffer, &Ip, 5) != -1 ) { // crack - if ( IsValidAmbePacket(Buffer, Ambe) ) + if ( IsValidAmbePacket(Buffer, &Codec1, Ambe1, &Codec2, Ambe2) ) { // tickle m_TimeoutTimer.Now(); @@ -191,9 +194,10 @@ void CCodecStream::Task(void) m_LocalQueue.pop(); // todo: check the PID // update content with transcoded ambe - Packet->SetAmbe(m_uiCodecOut, Ambe); + Packet->SetAmbe(Codec1, Ambe1); + Packet->SetAmbe(Codec2, Ambe2); // tag syncs in DvData - if ( (m_uiCodecOut == CODEC_AMBEPLUS) && (Packet->GetPacketId() % 21) == 0 ) + if ( ((Codec1 == CODEC_AMBEPLUS) || (Codec2 == CODEC_AMBEPLUS)) && (Packet->GetPacketId() % 21) == 0 ) { Packet->SetDvData(DStarSync); } @@ -240,13 +244,16 @@ void CCodecStream::Task(void) //////////////////////////////////////////////////////////////////////////////////////// /// packet decoding helpers -bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Ambe) +bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Codec1, uint8 *Ambe1, uint8 *Codec2, uint8 *Ambe2) { bool valid = false; - if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) ) + if ( (Buffer.size() == 21) && ((Buffer.data()[0] | Buffer.data()[1]) == m_uiCodecsOut) ) { - ::memcpy(Ambe, &(Buffer.data()[2]), 9); + *Codec1 = Buffer.data()[0]; + ::memcpy(Ambe1, &(Buffer.data()[3]), 9); + *Codec2 = Buffer.data()[1]; + ::memcpy(Ambe2, &(Buffer.data()[12]), 9); valid = true; } return valid; diff --git a/src/ccodecstream.h b/src/ccodecstream.h index c22e864..777f3d4 100644 --- a/src/ccodecstream.h +++ b/src/ccodecstream.h @@ -73,7 +73,7 @@ public: protected: // packet decoding helpers - bool IsValidAmbePacket(const CBuffer &, uint8 *); + bool IsValidAmbePacket(const CBuffer &, uint8 *, uint8 *, uint8 *, uint8 *); // packet encoding helpers void EncodeAmbePacket(CBuffer *, const uint8 *); @@ -85,7 +85,7 @@ protected: uint16 m_uiPort; uint8 m_uiPid; uint8 m_uiCodecIn; - uint8 m_uiCodecOut; + uint8 m_uiCodecsOut; // socket CIp m_Ip; diff --git a/src/cdcsclient.h b/src/cdcsclient.h index 2e579f4..2fd48f9 100644 --- a/src/cdcsclient.h +++ b/src/cdcsclient.h @@ -48,7 +48,6 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DCS; } const char *GetProtocolName(void) const { return "DCS"; } - int GetCodec(void) const { return CODEC_AMBEPLUS; } bool IsNode(void) const { return true; } // status diff --git a/src/cdcsprotocol.cpp b/src/cdcsprotocol.cpp index 27a0d79..21e38ca 100644 --- a/src/cdcsprotocol.cpp +++ b/src/cdcsprotocol.cpp @@ -220,7 +220,7 @@ bool CDcsProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) // get client callsign via = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, Header->GetCodec())) != NULL ) { // keep the handle m_Streams.push_back(stream); @@ -537,7 +537,7 @@ void CDcsProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFrameP uint8 tag[] = { '0','0','0','1' }; struct dstar_header DstarHeader; - Header.ConvertToDstarStruct(&DstarHeader); + Header.ConvertToDstarStruct(&DstarHeader, CODEC_AMBEPLUS); Buffer->Set(tag, sizeof(tag)); Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header) - sizeof(uint16)); diff --git a/src/cdextraclient.h b/src/cdextraclient.h index 453c5f4..2b42b65 100644 --- a/src/cdextraclient.h +++ b/src/cdextraclient.h @@ -49,7 +49,6 @@ public: int GetProtocol(void) const { return PROTOCOL_DEXTRA; } int GetProtocolRevision(void) const { return m_ProtRev; } const char *GetProtocolName(void) const { return "DExtra"; } - int GetCodec(void) const { return CODEC_AMBEPLUS; } bool IsNode(void) const { return true; } // status diff --git a/src/cdextraopenclient.cpp b/src/cdextraopenclient.cpp new file mode 100755 index 0000000..6dec3f2 --- /dev/null +++ b/src/cdextraopenclient.cpp @@ -0,0 +1,42 @@ +// +// cdextraopenclient.cpp +// xlxd +// +// Created by Antony Chazapis (SV9OAN) on 19/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include "cdextraopenclient.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// constructors + +CDextraOpenClient::CDextraOpenClient() + : CDextraClient() +{} + +CDextraOpenClient::CDextraOpenClient(const CCallsign &callsign, const CIp &ip, char reflectorModule, int protRev) + : CDextraClient(callsign, ip, reflectorModule, protRev) +{} + +CDextraOpenClient::CDextraOpenClient(const CDextraClient &client) + : CDextraClient(client) +{} diff --git a/src/cdextraopenclient.h b/src/cdextraopenclient.h new file mode 100644 index 0000000..7b78fd0 --- /dev/null +++ b/src/cdextraopenclient.h @@ -0,0 +1,54 @@ +// +// cdextraopenclient.h +// xlxd +// +// Created by Antony Chazapis (SV9OAN) on 19/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cdextraopenclient_h +#define cdextraopenclient_h + +#include "cdextraclient.h" + +//////////////////////////////////////////////////////////////////////////////////////// +// define + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CDextraOpenClient : public CDextraClient +{ +public: + // constructors + CDextraOpenClient(); + CDextraOpenClient(const CCallsign &, const CIp &, char = ' ', int = 0); + CDextraOpenClient(const CDextraClient &); + + // destructor + virtual ~CDextraOpenClient() {}; + + // identity + int GetProtocol(void) const { return PROTOCOL_DEXTRA_OPEN; } + const char *GetProtocolName(void) const { return "DExtra Open"; } +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cdextraopenclient_h */ diff --git a/src/cdextraopenprotocol.cpp b/src/cdextraopenprotocol.cpp new file mode 100644 index 0000000..59e1353 --- /dev/null +++ b/src/cdextraopenprotocol.cpp @@ -0,0 +1,98 @@ +// +// cdextraopenprotocol.cpp +// xlxd +// +// Created by Antony Chazapis (SV9OAN) on 19/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#include "main.h" +#include +#include "cdextraopenprotocol.h" +#include "cdextraopenclient.h" +#include "creflector.h" + + +//////////////////////////////////////////////////////////////////////////////////////// +// operation + +bool CDextraOpenProtocol::Init(void) +{ + bool ok; + + // base class + ok = CProtocol::Init(); + + // update the reflector callsign + m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)"ORF", 3); + + // create our socket + ok &= m_Socket.Open(DEXTRA_OPEN_PORT); + if ( !ok ) + { + std::cout << "Error opening socket on port UDP" << DEXTRA_OPEN_PORT << " on ip " << g_Reflector.GetListenIp() << std::endl; + } + + // update time + m_LastKeepaliveTime.Now(); + + // done + return ok; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// create client + +CClient *CDextraOpenProtocol::CreateClient(const CCallsign &callsign, const CIp &ip, char reflectormodule, int revision) const +{ + CClient *client = new CDextraOpenClient(callsign, ip, reflectormodule, revision); + return client; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// packet encoding helpers + +bool CDextraOpenProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const +{ + uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; + struct dstar_header DstarHeader; + + Packet.ConvertToDstarStruct(&DstarHeader, CODEC_CODEC2); + + Buffer->Set(tag, sizeof(tag)); + Buffer->Append(Packet.GetStreamId()); + Buffer->Append((uint8)0x80); + Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header)); + + return true; +} + +bool CDextraOpenProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buffer) const +{ + uint8 tag[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; + + Buffer->Set(tag, sizeof(tag)); + Buffer->Append(Packet.GetStreamId()); + Buffer->Append((uint8)(Packet.GetPacketId() % 21)); + Buffer->Append((uint8 *)Packet.GetCodec2(), AMBE_SIZE); + Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE); + + return true; + +} diff --git a/src/cdextraopenprotocol.h b/src/cdextraopenprotocol.h new file mode 100644 index 0000000..19962db --- /dev/null +++ b/src/cdextraopenprotocol.h @@ -0,0 +1,82 @@ +// +// cdextraopenprotocol.h +// xlxd +// +// Created by Antony Chazapis (SV9OAN) on 19/12/2018. +// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. +// +// ---------------------------------------------------------------------------- +// This file is part of xlxd. +// +// xlxd is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// xlxd is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Foobar. If not, see . +// ---------------------------------------------------------------------------- + +#ifndef cdextraopenprotocol_h +#define cdextraopenprotocol_h + +#include "cdextraprotocol.h" +#include "cdvheaderpacket.h" +#include "cdvframepacket.h" +#include "cclient.h" + +//////////////////////////////////////////////////////////////////////////////////////// + +// With the D-STAR vocoder extension by SV9OAN, voice in D-STAR streams can be encoded +// with either AMBE or Codec 2. Although the extension is backwards compatible and +// implementations can use the same reflector connections as AMBE-only clients, +// it should be avoided, to save the user confusion and establish interoperability. + +// By implementing another DExtra listener on a different port (30201 instead of 30001), +// xlxd can be used to bridge between the two formats. The new port is to be used by +// reflectors using the "ORF" prefix (Open ReFlector). + +// Any client connected to an ORF reflector will receive streams encoded with Codec 2. +// All other D-STAR protocol handlers will still send out data encoded with AMBE. +// Note that the protocol/port only affects data transmitted by the reflector. +// The stream vocoder is recognized by all protocol handlers, so a client can still +// transmit data using any vocoder on any port. The rationale behind this is that +// DExtra links may be used by repeaters or other reflectors, so it is not really +// possible to know what their clients support. So, nothing will change when linking +// a repeater to an XRF reflector, but will do when linking to an ORF one. + + +//////////////////////////////////////////////////////////////////////////////////////// +// class + +class CDextraOpenProtocol : public CDextraProtocol +{ +public: + // constructor + CDextraOpenProtocol() {}; + + // destructor + virtual ~CDextraOpenProtocol() {}; + + // initialization + bool Init(void); + + // identity + int GetProtocol(void) const { return PROTOCOL_DEXTRA_OPEN; } + +protected: + // create client + CClient *CreateClient(const CCallsign &, const CIp &, char, int) const; + + // packet encoding helpers + bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const; + bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const; +}; + +//////////////////////////////////////////////////////////////////////////////////////// +#endif /* cdextraopenprotocol_h */ diff --git a/src/cdextraprotocol.cpp b/src/cdextraprotocol.cpp index 8aa88ab..aed5dfc 100644 --- a/src/cdextraprotocol.cpp +++ b/src/cdextraprotocol.cpp @@ -24,8 +24,8 @@ #include "main.h" #include -#include "cdextraclient.h" #include "cdextraprotocol.h" +#include "cdextraclient.h" #include "creflector.h" #include "cgatekeeper.h" @@ -88,7 +88,7 @@ void CDextraProtocol::Task(void) //std::cout << "DExtra DV header:" << std::endl; // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_DEXTRA, Header->GetRpt2Module()) ) + if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, GetProtocol(), Header->GetRpt2Module()) ) { // handle it OnDvHeaderPacketIn(Header, Ip); @@ -110,7 +110,7 @@ void CDextraProtocol::Task(void) std::cout << "DExtra connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << " rev " << ProtRev << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_DEXTRA) ) + if ( g_GateKeeper.MayLink(Callsign, Ip, GetProtocol()) ) { // valid module ? if ( g_Reflector.IsValidModule(ToLinkModule) ) @@ -120,7 +120,7 @@ void CDextraProtocol::Task(void) m_Socket.Send(Buffer, Ip); // create the client - CDextraClient *client = new CDextraClient(Callsign, Ip, ToLinkModule, ProtRev); + CClient *client = CreateClient(Callsign, Ip, ToLinkModule, ProtRev); // and append g_Reflector.GetClients()->AddClient(client); @@ -148,7 +148,7 @@ void CDextraProtocol::Task(void) // find client & remove it CClients *clients = g_Reflector.GetClients(); - CClient *client = clients->FindClient(Ip, PROTOCOL_DEXTRA); + CClient *client = clients->FindClient(Ip, GetProtocol()); if ( client != NULL ) { // ack disconnect packet @@ -174,7 +174,7 @@ void CDextraProtocol::Task(void) CClients *clients = g_Reflector.GetClients(); int index = -1; CClient *client = NULL; - while ( (client = clients->FindNextClient(Callsign, Ip, PROTOCOL_DEXTRA, &index)) != NULL ) + while ( (client = clients->FindNextClient(Callsign, Ip, GetProtocol(), &index)) != NULL ) { client->Alive(); } @@ -204,6 +204,15 @@ void CDextraProtocol::Task(void) } } +//////////////////////////////////////////////////////////////////////////////////////// +// create client + +CClient *CDextraProtocol::CreateClient(const CCallsign &callsign, const CIp &ip, char reflectormodule, int revision) const +{ + CClient *client = new CDextraClient(callsign, ip, reflectormodule, revision); + return client; +} + //////////////////////////////////////////////////////////////////////////////////////// // queue helper @@ -224,7 +233,7 @@ void CDextraProtocol::HandleQueue(void) CClients *clients = g_Reflector.GetClients(); int index = -1; CClient *client = NULL; - while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, &index)) != NULL ) + while ( (client = clients->FindNextClient(GetProtocol(), &index)) != NULL ) { // is this client busy ? if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) ) @@ -262,7 +271,7 @@ void CDextraProtocol::HandleKeepalives(void) CClients *clients = g_Reflector.GetClients(); int index = -1; CClient *client = NULL; - while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, &index)) != NULL ) + while ( (client = clients->FindNextClient(GetProtocol(), &index)) != NULL ) { // send keepalive m_Socket.Send(keepalive, client->GetIp()); @@ -305,7 +314,7 @@ bool CDextraProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) CCallsign via(Header->GetRpt1Callsign()); // find this client - CClient *client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_DEXTRA); + CClient *client = g_Reflector.GetClients()->FindClient(Ip, GetProtocol()); if ( client != NULL ) { // get client callsign @@ -318,7 +327,7 @@ bool CDextraProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) Header->SetRpt2Module(client->GetReflectorModule()); } // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, Header->GetCodec())) != NULL ) { // keep the handle m_Streams.push_back(stream); @@ -521,7 +530,7 @@ bool CDextraProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffe uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; struct dstar_header DstarHeader; - Packet.ConvertToDstarStruct(&DstarHeader); + Packet.ConvertToDstarStruct(&DstarHeader, CODEC_AMBEPLUS); Buffer->Set(tag, sizeof(tag)); Buffer->Append(Packet.GetStreamId()); diff --git a/src/cdextraprotocol.h b/src/cdextraprotocol.h index 3c623fc..abb7d1c 100644 --- a/src/cdextraprotocol.h +++ b/src/cdextraprotocol.h @@ -30,6 +30,7 @@ #include "cdvheaderpacket.h" #include "cdvframepacket.h" #include "cdvlastframepacket.h" +#include "cclient.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -70,7 +71,13 @@ public: // task void Task(void); + // identity + int GetProtocol(void) const { return PROTOCOL_DEXTRA; } + protected: + // create client + CClient *CreateClient(const CCallsign &, const CIp &, char, int) const; + // queue helper void HandleQueue(void); diff --git a/src/cdmrmmdvmclient.h b/src/cdmrmmdvmclient.h index b5880ab..a737326 100644 --- a/src/cdmrmmdvmclient.h +++ b/src/cdmrmmdvmclient.h @@ -48,7 +48,6 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DMRMMDVM; } const char *GetProtocolName(void) const { return "DMRMmdvm"; } - int GetCodec(void) const { return CODEC_AMBE2PLUS; } bool IsNode(void) const { return true; } // status diff --git a/src/cdmrmmdvmprotocol.cpp b/src/cdmrmmdvmprotocol.cpp index 2398fd1..431bbb7 100644 --- a/src/cdmrmmdvmprotocol.cpp +++ b/src/cdmrmmdvmprotocol.cpp @@ -328,7 +328,7 @@ bool CDmrmmdvmProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &I if ( g_Reflector.IsValidModule(Header->GetRpt2Module()) && (CallType == DMR_GROUP_CALL) ) { // yes, try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, CODEC_AMBE2PLUS)) != NULL ) { // keep the handle m_Streams.push_back(stream); diff --git a/src/cdmrplusclient.h b/src/cdmrplusclient.h index 628b2a4..56cb963 100644 --- a/src/cdmrplusclient.h +++ b/src/cdmrplusclient.h @@ -48,7 +48,6 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DMRPLUS; } const char *GetProtocolName(void) const { return "DMRplus"; } - int GetCodec(void) const { return CODEC_AMBE2PLUS; } bool IsNode(void) const { return true; } // status diff --git a/src/cdmrplusprotocol.cpp b/src/cdmrplusprotocol.cpp index 1d1180f..4b3d6b6 100644 --- a/src/cdmrplusprotocol.cpp +++ b/src/cdmrplusprotocol.cpp @@ -219,7 +219,7 @@ bool CDmrplusProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip if ( client != NULL ) { // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, CODEC_AMBE2PLUS)) != NULL ) { // keep the handle m_Streams.push_back(stream); diff --git a/src/cdplusclient.h b/src/cdplusclient.h index d615e12..c8ed9e1 100644 --- a/src/cdplusclient.h +++ b/src/cdplusclient.h @@ -48,7 +48,6 @@ public: // identity int GetProtocol(void) const { return PROTOCOL_DPLUS; } const char *GetProtocolName(void) const { return "DPlus"; } - int GetCodec(void) const { return CODEC_AMBEPLUS; } bool IsNode(void) const { return true; } bool IsDextraDongle(void) const { return m_bDextraDongle; } void SetDextraDongle(void) { m_bDextraDongle = true; } diff --git a/src/cdplusprotocol.cpp b/src/cdplusprotocol.cpp index 86aa4fb..097524f 100644 --- a/src/cdplusprotocol.cpp +++ b/src/cdplusprotocol.cpp @@ -225,7 +225,7 @@ bool CDplusProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) // get client callsign via = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, Header->GetCodec())) != NULL ) { // keep the handle m_Streams.push_back(stream); @@ -552,7 +552,7 @@ bool CDplusProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer uint8 tag[] = { 0x3A,0x80,0x44,0x53,0x56,0x54,0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 }; struct dstar_header DstarHeader; - Packet.ConvertToDstarStruct(&DstarHeader); + Packet.ConvertToDstarStruct(&DstarHeader, CODEC_AMBEPLUS); Buffer->Set(tag, sizeof(tag)); Buffer->Append(Packet.GetStreamId()); diff --git a/src/cdvframepacket.cpp b/src/cdvframepacket.cpp index 113aba4..fa31007 100644 --- a/src/cdvframepacket.cpp +++ b/src/cdvframepacket.cpp @@ -34,6 +34,7 @@ CDvFramePacket::CDvFramePacket() { ::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); + ::memset(m_uiCodec2, 0, sizeof(m_uiCodec2)); ::memset(m_uiDvData, 0, sizeof(m_uiDvData)); ::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus)); ::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); @@ -45,6 +46,7 @@ CDvFramePacket::CDvFramePacket(const struct dstar_dvframe *dvframe, uint16 sid, : CPacket(sid, pid) { ::memcpy(m_uiAmbe, dvframe->AMBE, sizeof(m_uiAmbe)); + ::memset(m_uiCodec2, 0, sizeof(m_uiCodec2)); ::memcpy(m_uiDvData, dvframe->DVDATA, sizeof(m_uiDvData)); ::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus)); ::memset(m_uiDvSync, 0, sizeof(m_uiDvSync)); @@ -58,18 +60,20 @@ CDvFramePacket::CDvFramePacket(const uint8 *ambe, const uint8 *sync, uint16 sid, ::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus)); ::memcpy(m_uiDvSync, sync, sizeof(m_uiDvSync)); ::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); + ::memset(m_uiCodec2, 0, sizeof(m_uiCodec2)); ::memset(m_uiDvData, 0, sizeof(m_uiDvData)); } -// dstar + dmr constructor +// dstar + codec 2 + dmr constructor CDvFramePacket::CDvFramePacket (uint16 sid, - uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata, + uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstarcodec2, const uint8 *dstardvdata, uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync) : CPacket(sid, dstarpid, dmrpid, dprspid) { ::memcpy(m_uiAmbe, dstarambe, sizeof(m_uiAmbe)); + ::memcpy(m_uiCodec2, dstarcodec2, sizeof(m_uiCodec2)); ::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData)); ::memcpy(m_uiAmbePlus, dmrambe, sizeof(m_uiAmbePlus)); ::memcpy(m_uiDvSync, dmrsync, sizeof(m_uiDvSync)); @@ -81,6 +85,7 @@ CDvFramePacket::CDvFramePacket(const CDvFramePacket &DvFrame) : CPacket(DvFrame) { ::memcpy(m_uiAmbe, DvFrame.m_uiAmbe, sizeof(m_uiAmbe)); + ::memcpy(m_uiCodec2, DvFrame.m_uiCodec2, sizeof(m_uiCodec2)); ::memcpy(m_uiDvData, DvFrame.m_uiDvData, sizeof(m_uiDvData)); ::memcpy(m_uiAmbePlus, DvFrame.m_uiAmbePlus, sizeof(m_uiAmbePlus)); ::memcpy(m_uiDvSync, DvFrame.m_uiDvSync, sizeof(m_uiDvSync)); @@ -103,6 +108,7 @@ 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; default: return NULL; } } @@ -123,11 +129,29 @@ void CDvFramePacket::SetAmbe(uint8 uiCodec, uint8 *Ambe) ::memcpy(m_uiAmbe, Ambe, sizeof(m_uiAmbe)); break; case CODEC_AMBE2PLUS: - ::memcpy(m_uiAmbePlus, Ambe, sizeof(m_uiAmbe)); + ::memcpy(m_uiAmbePlus, Ambe, sizeof(m_uiAmbePlus)); + break; + case CODEC_CODEC2: + ::memcpy(m_uiCodec2, Ambe, sizeof(m_uiCodec2)); break; } } +void CDvFramePacket::ClearAmbe(uint8 uiCodec) +{ + switch (uiCodec) + { + case CODEC_AMBEPLUS: + ::memset(m_uiAmbe, 0, sizeof(m_uiAmbe)); + break; + case CODEC_AMBE2PLUS: + ::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus)); + break; + case CODEC_CODEC2: + ::memset(m_uiCodec2, 0, sizeof(m_uiCodec2)); + break; + } +} //////////////////////////////////////////////////////////////////////////////////////// // operators @@ -135,6 +159,7 @@ void CDvFramePacket::SetAmbe(uint8 uiCodec, uint8 *Ambe) bool CDvFramePacket::operator ==(const CDvFramePacket &DvFrame) const { return ( (::memcmp(m_uiAmbe, DvFrame.m_uiAmbe, sizeof(m_uiAmbe)) == 0) && + (::memcmp(m_uiCodec2, DvFrame.m_uiCodec2, sizeof(m_uiCodec2)) == 0) && (::memcmp(m_uiDvData, DvFrame.m_uiDvData, sizeof(m_uiDvData)) == 0) && (::memcmp(m_uiAmbePlus, DvFrame.m_uiAmbePlus, sizeof(m_uiAmbePlus)) == 0) && (::memcmp(m_uiDvSync, DvFrame.m_uiDvSync, sizeof(m_uiDvSync)) == 0) ); diff --git a/src/cdvframepacket.h b/src/cdvframepacket.h index 69917b7..477d8ee 100644 --- a/src/cdvframepacket.h +++ b/src/cdvframepacket.h @@ -55,7 +55,7 @@ public: CDvFramePacket(); CDvFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); - CDvFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); + CDvFramePacket(uint16, uint8, const uint8 *, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvFramePacket(const CDvFramePacket &); // destructor @@ -72,12 +72,14 @@ public: const uint8 *GetAmbe(uint8) const; const uint8 *GetAmbe(void) const { return m_uiAmbe; } const uint8 *GetAmbePlus(void) const { return m_uiAmbePlus; } + const uint8 *GetCodec2(void) const { return m_uiCodec2; } const uint8 *GetDvData(void) const { return m_uiDvData; } const uint8 *GetDvSync(void) const { return m_uiDvSync; } // set void SetDvData(uint8 *); void SetAmbe(uint8, uint8 *); + void ClearAmbe(uint8); // operators bool operator ==(const CDvFramePacket &) const; @@ -86,10 +88,12 @@ protected: // get uint8 *GetAmbeData(void) { return m_uiAmbe; } uint8 *GetAmbePlusData(void) { return m_uiAmbePlus; } + uint8 *GetCodec2Data(void) { return m_uiCodec2; } protected: // data (dstar) uint8 m_uiAmbe[AMBE_SIZE]; + uint8 m_uiCodec2[AMBE_SIZE]; uint8 m_uiDvData[DVDATA_SIZE]; // data (dmr) uint8 m_uiAmbePlus[AMBEPLUS_SIZE]; diff --git a/src/cdvheaderpacket.cpp b/src/cdvheaderpacket.cpp index 0ee30d0..161df32 100644 --- a/src/cdvheaderpacket.cpp +++ b/src/cdvheaderpacket.cpp @@ -97,12 +97,12 @@ CPacket *CDvHeaderPacket::Duplicate(void) const //////////////////////////////////////////////////////////////////////////////////////// // conversion -void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer) const +void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer, uint8 CodecOut) const { ::memset(buffer, 0, sizeof(struct dstar_header)); buffer->Flag1 = m_uiFlag1; buffer->Flag2 = m_uiFlag2; - buffer->Flag3 = m_uiFlag3; + buffer->Flag3 = (CodecOut == CODEC_AMBEPLUS) ? 0x00 : 0x01 ; m_csUR.GetCallsign(buffer->UR); m_csRPT1.GetCallsign(buffer->RPT1); m_csRPT2.GetCallsign(buffer->RPT2); @@ -127,6 +127,24 @@ bool CDvHeaderPacket::IsValid(void) const } +//////////////////////////////////////////////////////////////////////////////////////// +// get codec + +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. + if ( m_uiFlag3 == 0x01 ) + { + return CODEC_CODEC2; + } + + return CODEC_AMBEPLUS; +} + + //////////////////////////////////////////////////////////////////////////////////////// // operators diff --git a/src/cdvheaderpacket.h b/src/cdvheaderpacket.h index 28cb771..daf27bd 100644 --- a/src/cdvheaderpacket.h +++ b/src/cdvheaderpacket.h @@ -75,10 +75,13 @@ public: bool IsDvHeader(void) const { return true; } // conversion - void ConvertToDstarStruct(struct dstar_header *) const; + void ConvertToDstarStruct(struct dstar_header *, uint8) const; // get valid bool IsValid(void) const; + + // get codec + uint8 GetCodec(void) const; // get callsigns const CCallsign &GetUrCallsign(void) const { return m_csUR; } diff --git a/src/cdvlastframepacket.cpp b/src/cdvlastframepacket.cpp index 5908303..5022612 100644 --- a/src/cdvlastframepacket.cpp +++ b/src/cdvlastframepacket.cpp @@ -51,9 +51,9 @@ CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, const uint8 *sync, uin CDvLastFramePacket::CDvLastFramePacket (uint16 sid, - uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata, + uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstarcodec2, const uint8 *dstardvdata, uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync) - : CDvFramePacket(sid, dstarpid, dstarambe, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync) + : CDvFramePacket(sid, dstarpid, dstarambe, dstarcodec2, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync) { } diff --git a/src/cdvlastframepacket.h b/src/cdvlastframepacket.h index 685e9d4..a7d8d9f 100644 --- a/src/cdvlastframepacket.h +++ b/src/cdvlastframepacket.h @@ -42,7 +42,7 @@ public: CDvLastFramePacket(); CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8); CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8); - CDvLastFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); + CDvLastFramePacket(uint16, uint8, const uint8 *, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *); CDvLastFramePacket(const CDvLastFramePacket &); // destructor diff --git a/src/cgatekeeper.cpp b/src/cgatekeeper.cpp index fb2d0b0..11aeca2 100644 --- a/src/cgatekeeper.cpp +++ b/src/cgatekeeper.cpp @@ -97,6 +97,7 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol { // repeaters case PROTOCOL_DEXTRA: + case PROTOCOL_DEXTRA_OPEN: case PROTOCOL_DPLUS: case PROTOCOL_DCS: case PROTOCOL_DMRPLUS: @@ -137,6 +138,7 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, int prot // repeaters, protocol specific case PROTOCOL_ANY: case PROTOCOL_DEXTRA: + case PROTOCOL_DEXTRA_OPEN: case PROTOCOL_DPLUS: case PROTOCOL_DCS: case PROTOCOL_DMRPLUS: diff --git a/src/cpacketstream.cpp b/src/cpacketstream.cpp index 27776b7..b0c4f41 100644 --- a/src/cpacketstream.cpp +++ b/src/cpacketstream.cpp @@ -34,13 +34,14 @@ CPacketStream::CPacketStream() m_uiStreamId = 0; m_uiPacketCntr = 0; m_OwnerClient = NULL; + m_CodecIn = CODEC_NONE; m_CodecStream = NULL; } //////////////////////////////////////////////////////////////////////////////////////// // open / close -bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client) +bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client, uint8 CodecIn) { bool ok = false; @@ -54,7 +55,8 @@ bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client) m_DvHeader = DvHeader; m_OwnerClient = client; m_LastPacketTime.Now(); - m_CodecStream = g_Transcoder.GetStream(this, client->GetCodec()); + m_CodecIn = CodecIn; + m_CodecStream = g_Transcoder.GetStream(this, CodecIn); ok = true; } return ok; @@ -67,6 +69,7 @@ void CPacketStream::Close(void) m_uiStreamId = 0; m_OwnerClient = NULL; g_Transcoder.ReleaseStream(m_CodecStream); + m_CodecIn = CODEC_NONE; m_CodecStream = NULL; } diff --git a/src/cpacketstream.h b/src/cpacketstream.h index c910158..df8a0ec 100644 --- a/src/cpacketstream.h +++ b/src/cpacketstream.h @@ -48,7 +48,7 @@ public: virtual ~CPacketStream() {}; // open / close - bool Open(const CDvHeaderPacket &, CClient *); + bool Open(const CDvHeaderPacket &, CClient *, uint8); void Close(void); // push & pop @@ -63,6 +63,7 @@ public: bool IsOpen(void) const { return m_bOpen; } uint16 GetStreamId(void) const { return m_uiStreamId; } const CCallsign &GetUserCallsign(void) const { return m_DvHeader.GetMyCallsign(); } + uint8 GetCodec(void) const { return m_CodecIn; } protected: // data @@ -72,6 +73,7 @@ protected: CClient *m_OwnerClient; CTimePoint m_LastPacketTime; CDvHeaderPacket m_DvHeader; + uint8 m_CodecIn; CCodecStream *m_CodecStream; }; diff --git a/src/cprotocol.cpp b/src/cprotocol.cpp index a5d2adb..673a971 100644 --- a/src/cprotocol.cpp +++ b/src/cprotocol.cpp @@ -140,6 +140,13 @@ void CProtocol::OnDvFramePacketIn(CDvFramePacket *Frame, const CIp *Ip) CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip); if ( stream != NULL ) { + // place the voice data in the appropriate place + if ( stream->GetCodec() == CODEC_CODEC2 ) + { + Frame->SetAmbe(CODEC_CODEC2, (uint8 *)Frame->GetAmbe()); + Frame->ClearAmbe(CODEC_AMBEPLUS); + } + //std::cout << "DV frame" << "from " << *Ip << std::endl; // and push stream->Lock(); @@ -154,6 +161,13 @@ void CProtocol::OnDvLastFramePacketIn(CDvLastFramePacket *Frame, const CIp *Ip) CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip); if ( stream != NULL ) { + // place the voice data in the appropriate place + if ( stream->GetCodec() == CODEC_CODEC2 ) + { + Frame->SetAmbe(CODEC_CODEC2, (uint8 *)Frame->GetAmbe()); + Frame->ClearAmbe(CODEC_AMBEPLUS); + } + // push stream->Lock(); stream->Push(Frame); diff --git a/src/cprotocols.cpp b/src/cprotocols.cpp index 53f5499..d570d2a 100644 --- a/src/cprotocols.cpp +++ b/src/cprotocols.cpp @@ -24,6 +24,7 @@ #include "main.h" #include "cdextraprotocol.h" +#include "cdextraopenprotocol.h" #include "cdplusprotocol.h" #include "cdcsprotocol.h" #include "cxlxprotocol.h" @@ -67,35 +68,40 @@ bool CProtocols::Init(void) m_Mutex.lock(); { - // create and initialize DEXTRA + // create and initialize DEXTRA (AMBE output) delete m_Protocols[0]; m_Protocols[0] = new CDextraProtocol; ok &= m_Protocols[0]->Init(); - // create and initialize DPLUS + // create and initialize DEXTRA (Codec 2 output) delete m_Protocols[1]; - m_Protocols[1] = new CDplusProtocol; + m_Protocols[1] = new CDextraOpenProtocol; ok &= m_Protocols[1]->Init(); - // create and initialize DCS + // create and initialize DPLUS delete m_Protocols[2]; - m_Protocols[2] = new CDcsProtocol; + m_Protocols[2] = new CDplusProtocol; ok &= m_Protocols[2]->Init(); - // create and initialize XLX - interlink + // create and initialize DCS delete m_Protocols[3]; - m_Protocols[3] = new CXlxProtocol; + m_Protocols[3] = new CDcsProtocol; ok &= m_Protocols[3]->Init(); - // create and initialize DMRPLUS + // create and initialize XLX - interlink delete m_Protocols[4]; - m_Protocols[4] = new CDmrplusProtocol; + m_Protocols[4] = new CXlxProtocol; ok &= m_Protocols[4]->Init(); - // create and initialize DMRMMDVM + // create and initialize DMRPLUS delete m_Protocols[5]; - m_Protocols[5] = new CDmrmmdvmProtocol; + m_Protocols[5] = new CDmrplusProtocol; ok &= m_Protocols[5]->Init(); + + // create and initialize DMRMMDVM + delete m_Protocols[6]; + m_Protocols[6] = new CDmrmmdvmProtocol; + ok &= m_Protocols[6]->Init(); } m_Mutex.unlock(); diff --git a/src/creflector.cpp b/src/creflector.cpp index ed6ba58..9df75ed 100644 --- a/src/creflector.cpp +++ b/src/creflector.cpp @@ -183,7 +183,7 @@ bool CReflector::IsStreaming(char module) return false; } -CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client) +CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client, uint8 CodecIn) { CPacketStream *retStream = NULL; @@ -208,7 +208,7 @@ CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client // lock it stream->Lock(); // is it available ? - if ( stream->Open(*DvHeader, client) ) + if ( stream->Open(*DvHeader, client, CodecIn) ) { // stream open, mark client as master // so that it can't be deleted diff --git a/src/creflector.h b/src/creflector.h index 1424453..c05a117 100644 --- a/src/creflector.h +++ b/src/creflector.h @@ -75,7 +75,7 @@ public: void ReleasePeers(void) { m_Peers.Unlock(); } // stream opening & closing - CPacketStream *OpenStream(CDvHeaderPacket *, CClient *); + CPacketStream *OpenStream(CDvHeaderPacket *, CClient *, uint8 CodecIn); bool IsStreaming(char); void CloseStream(CPacketStream *); diff --git a/src/ctranscoder.cpp b/src/ctranscoder.cpp index 6b810c9..5b96e08 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, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS); + EncodeOpenstreamPacket(&Buffer, uiCodecIn, CODEC_ALL ^ 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, (uiCodecIn == CODEC_AMBEPLUS) ? CODEC_AMBE2PLUS : CODEC_AMBEPLUS); + stream = new CCodecStream(PacketStream, m_StreamidOpenStream, uiCodecIn, CODEC_ALL ^ uiCodecIn); // init it if ( stream->Init(m_PortOpenStream) ) @@ -381,14 +381,14 @@ void CTranscoder::EncodeKeepAlivePacket(CBuffer *Buffer) Buffer->Append((uint8 *)(const char *)g_Reflector.GetCallsign(), CALLSIGN_LEN); } -void CTranscoder::EncodeOpenstreamPacket(CBuffer *Buffer, uint8 uiCodecIn, uint8 uiCodecOut) +void CTranscoder::EncodeOpenstreamPacket(CBuffer *Buffer, uint8 uiCodecIn, uint8 uiCodecsOut) { uint8 tag[] = { 'A','M','B','E','D','O','S' }; Buffer->Set(tag, sizeof(tag)); Buffer->Append((uint8 *)(const char *)g_Reflector.GetCallsign(), CALLSIGN_LEN); Buffer->Append((uint8)uiCodecIn); - Buffer->Append((uint8)uiCodecOut); + Buffer->Append((uint8)uiCodecsOut); } void CTranscoder::EncodeClosestreamPacket(CBuffer *Buffer, uint16 uiStreamId) diff --git a/src/cxlxclient.cpp b/src/cxlxclient.cpp index 2d32b29..e7b7fa7 100644 --- a/src/cxlxclient.cpp +++ b/src/cxlxclient.cpp @@ -62,6 +62,9 @@ int CXlxClient::GetCodec(void) const codec = CODEC_AMBEPLUS; break; case XLX_PROTOCOL_REVISION_2: + codec = CODEC_AMBEPLUS; // transcode again anyway + break; + case XLX_PROTOCOL_REVISION_3: codec = CODEC_NONE; break; } diff --git a/src/cxlxclient.h b/src/cxlxclient.h index ae15045..13ff1a8 100644 --- a/src/cxlxclient.h +++ b/src/cxlxclient.h @@ -33,7 +33,8 @@ #define XLX_PROTOCOL_REVISION_0 0 // AMBE only, original connect mechanism #define XLX_PROTOCOL_REVISION_1 1 // AMBE only, revised connect mechanism -#define XLX_PROTOCOL_REVISION_2 2 // Transcoded AMBE+AMBE2 interlink +#define XLX_PROTOCOL_REVISION_2 2 // Transcoded AMBE+AMBE2 interlink (use AMBE only) +#define XLX_PROTOCOL_REVISION_3 3 // Transcoded AMBE+AMBE2+Codec 2 interlink //////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/cxlxpeer.cpp b/src/cxlxpeer.cpp index aa214c4..e074e1d 100644 --- a/src/cxlxpeer.cpp +++ b/src/cxlxpeer.cpp @@ -93,7 +93,11 @@ int CXlxPeer::GetProtocolRevision(const CVersion &version) { int protrev = XLX_PROTOCOL_REVISION_0; - if ( version.IsEqualOrHigherTo(CVersion(2,2,0)) ) + if ( version.IsEqualOrHigherTo(CVersion(3,0,0)) ) + { + protrev = XLX_PROTOCOL_REVISION_3; + } + else if ( version.IsEqualOrHigherTo(CVersion(2,2,0)) ) { protrev = XLX_PROTOCOL_REVISION_2; } diff --git a/src/cxlxprotocol.cpp b/src/cxlxprotocol.cpp index f01fb9a..72039f8 100644 --- a/src/cxlxprotocol.cpp +++ b/src/cxlxprotocol.cpp @@ -137,6 +137,7 @@ void CXlxProtocol::Task(void) break; case XLX_PROTOCOL_REVISION_1: case XLX_PROTOCOL_REVISION_2: + case XLX_PROTOCOL_REVISION_3: default: // acknowledge the request EncodeConnectAckPacket(&Buffer, Modules); @@ -425,7 +426,7 @@ bool CXlxProtocol::OnDvHeaderPacketIn(CDvHeaderPacket *Header, const CIp &Ip) if ( client != NULL ) { // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != NULL ) + if ( (stream = g_Reflector.OpenStream(Header, client, ((CXlxClient *)client)->GetCodec())) != NULL ) { // keep the handle m_Streams.push_back(stream); @@ -560,15 +561,32 @@ CDvFramePacket *CXlxProtocol::IsValidDvFramePacket(const CBuffer &Buffer) (Buffer.size() == 45) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && ((Buffer.data()[14] & 0x40) == 0) ) + { + // create packet + dvframe = new CDvFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), + *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]); + // check validity of packet + if ( !dvframe->IsValid() ) + { + delete dvframe; + dvframe = NULL; + } + } + + // otherwise try protocol revision 3 + if ( (dvframe == NULL) && + (Buffer.size() == 54) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && + (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && + ((Buffer.data()[14] & 0x40) == 0) ) { // create packet dvframe = new CDvFramePacket( // sid *((uint16 *)&(Buffer.data()[12])), // dstar - Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), + Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), &(Buffer.data()[33]), // dmr - Buffer.data()[27], Buffer.data()[28], &(Buffer.data()[29]), &(Buffer.data()[38])); + Buffer.data()[36], Buffer.data()[37], &(Buffer.data()[38]), &(Buffer.data()[47])); // check validity of packet if ( !dvframe->IsValid() ) @@ -594,15 +612,32 @@ CDvLastFramePacket *CXlxProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer (Buffer.size() == 45) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && ((Buffer.data()[14] & 0x40) != 0) ) + { + // create packet + dvframe = new CDvLastFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), + *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]); + // check validity of packet + if ( !dvframe->IsValid() ) + { + delete dvframe; + dvframe = NULL; + } + } + + // otherwise try protocol revision 3 + if ( (dvframe == NULL) && + (Buffer.size() == 54) && (Buffer.Compare((uint8 *)"DSVT", 4) == 0) && + (Buffer.data()[4] == 0x20) && (Buffer.data()[8] == 0x20) && + ((Buffer.data()[14] & 0x40) != 0) ) { // create packet dvframe = new CDvLastFramePacket( // sid *((uint16 *)&(Buffer.data()[12])), // dstar - Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), + Buffer.data()[14], &(Buffer.data()[15]), &(Buffer.data()[24]), &(Buffer.data()[33]), // dmr - Buffer.data()[27], Buffer.data()[28], &(Buffer.data()[29]), &(Buffer.data()[38])); + Buffer.data()[36], Buffer.data()[37], &(Buffer.data()[38]), &(Buffer.data()[47])); // check validity of packet if ( !dvframe->IsValid() ) @@ -692,6 +727,7 @@ bool CXlxProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Bu Buffer->Append(Packet.GetStreamId()); Buffer->Append((uint8)(Packet.GetDstarPacketId() % 21)); Buffer->Append((uint8 *)Packet.GetAmbe(), AMBE_SIZE); + Buffer->Append((uint8 *)Packet.GetCodec2(), AMBE_SIZE); Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE); Buffer->Append((uint8)Packet.GetDmrPacketId()); @@ -713,6 +749,7 @@ bool CXlxProtocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBu Buffer->Append(Packet.GetStreamId()); Buffer->Append((uint8)((Packet.GetPacketId() % 21) | 0x40)); Buffer->Append(dstarambe, sizeof(dstarambe)); + Buffer->Append(dstarambe, sizeof(dstarambe)); Buffer->Append(dstardvdata, sizeof(dstardvdata)); diff --git a/src/cxlxprotocol.h b/src/cxlxprotocol.h index 1b8d8d9..e4ffc36 100644 --- a/src/cxlxprotocol.h +++ b/src/cxlxprotocol.h @@ -52,6 +52,9 @@ public: // task void Task(void); + // identity + int GetProtocol(void) const { return PROTOCOL_XLX; } + protected: // queue helper void HandleQueue(void); diff --git a/src/main.h b/src/main.h index fa7acab..3c3d22a 100644 --- a/src/main.h +++ b/src/main.h @@ -47,9 +47,9 @@ // version ----------------------------------------------------- -#define VERSION_MAJOR 2 -#define VERSION_MINOR 2 -#define VERSION_REVISION 2 +#define VERSION_MAJOR 3 +#define VERSION_MINOR 0 +#define VERSION_REVISION 0 // global ------------------------------------------------------ @@ -65,22 +65,26 @@ // protocols --------------------------------------------------- -#define NB_OF_PROTOCOLS 6 +#define NB_OF_PROTOCOLS 7 #define PROTOCOL_ANY -1 #define PROTOCOL_NONE 0 #define PROTOCOL_DEXTRA 1 -#define PROTOCOL_DPLUS 2 -#define PROTOCOL_DCS 3 -#define PROTOCOL_XLX 4 -#define PROTOCOL_DMRPLUS 5 -#define PROTOCOL_DMRMMDVM 6 - -// DExtra +#define PROTOCOL_DEXTRA_OPEN 2 +#define PROTOCOL_DPLUS 3 +#define PROTOCOL_DCS 4 +#define PROTOCOL_XLX 5 +#define PROTOCOL_DMRPLUS 6 +#define PROTOCOL_DMRMMDVM 7 + +// DExtra (AMBE output) #define DEXTRA_PORT 30001 // UDP port #define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds #define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds +// DExtra (Codec 2 output) +#define DEXTRA_OPEN_PORT 30201 // UDP port + // DPlus #define DPLUS_PORT 20001 // UDP port #define DPLUS_KEEPALIVE_PERIOD 1 // in seconds @@ -123,6 +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 // DMRid database -----------------------------------------------