From 9581d729a7de48a4f53973d7999b9f35a9a53236 Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Mon, 11 Feb 2019 18:43:36 +0200 Subject: [PATCH] Implement the "vocoder extension" to use Codec 2 with D-STAR Implementation of the "vocoder extension" by SV9OAN, as described in https://github.com/chazapis/pydv, which allows the use of the open source Codec 2 with D-STAR. With the changes here, xlxd/ambed can be used to transcode and bridge the two formats. The solution implemented uses an additional DExtra listener on a different port (30201 instead of 30001). 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. Summary of code changes in xlxd: * Added protocol "DExtra Open", listening on port 30201. The protocol handler is subclassed from DExtra. Minor changes were required to make the DExtra implementation more "abstract" to allow that. * Codec used no longer a protocol client property. All D-STAR protocol handlers use the header to determine the protocol. DMR protocol handlers just specify the appropriate codec when opening a stream. * DV frames now also include Codec 2 data. * Interface with ambed changed to 1 codec in, 2 codecs out. * Interface with other xlx peers changed to accommodate the enlarged DV frames, so compatible peers will exchange fully transcoded streams. * Major version changed to 3, to recognize peer compatibility. Summary of code changes to ambed: * Added (virtual) interface class for Codec 2. * Vocodec channels now have 3 interfaces (1 in, 2 out) and are grouped together in triplets. Each group contains all possible permutations of respective interfaces - 3 channels. Only one channel from each group can be used at a given time. * When an incoming packet is decoded in the interface loop, it is duplicated and sent to two separate voice queues (one for each outgoing codec). * Interface changed to 1 codec in, 2 codecs out. * Major version changed to 2, as the interface is incompatible with previous versions. --- ambed/ccodec2interface.cpp | 242 +++++++++++++++++++++++++++++ ambed/ccodec2interface.h | 68 ++++++++ ambed/ccontroller.cpp | 26 ++-- ambed/ccontroller.h | 2 +- ambed/cftdidevicedescr.cpp | 302 ++++++++++++++---------------------- ambed/cftdidevicedescr.h | 1 + ambed/cstream.cpp | 74 +++++++-- ambed/cstream.h | 13 +- ambed/cusb3000interface.cpp | 37 ----- ambed/cusb3000interface.h | 4 - ambed/cusb3003interface.cpp | 44 ------ ambed/cusb3003interface.h | 4 - ambed/cusb3xxxinterface.cpp | 74 +++++++-- ambed/cvocodecchannel.cpp | 81 ++++++++-- ambed/cvocodecchannel.h | 58 ++++--- ambed/cvocodecinterface.cpp | 46 +++++- ambed/cvocodecinterface.h | 17 +- ambed/cvocodecs.cpp | 15 +- ambed/cvoicepacket.cpp | 5 + ambed/main.h | 11 +- ambed/makefile | 2 +- ambedtest/ccodecstream.cpp | 22 ++- ambedtest/ccodecstream.h | 4 +- ambedtest/ctranscoder.cpp | 8 +- ambedtest/main.cpp | 13 +- ambedtest/main.h | 4 +- src/cbmclient.h | 1 - src/cclient.h | 1 - src/ccodecstream.cpp | 25 +-- src/ccodecstream.h | 4 +- src/cdcsclient.h | 1 - src/cdcsprotocol.cpp | 4 +- src/cdextraclient.h | 1 - src/cdextraopenclient.cpp | 42 +++++ src/cdextraopenclient.h | 54 +++++++ src/cdextraopenprotocol.cpp | 98 ++++++++++++ src/cdextraopenprotocol.h | 82 ++++++++++ src/cdextraprotocol.cpp | 31 ++-- src/cdextraprotocol.h | 7 + src/cdmrmmdvmclient.h | 1 - src/cdmrmmdvmprotocol.cpp | 2 +- src/cdmrplusclient.h | 1 - src/cdmrplusprotocol.cpp | 2 +- src/cdplusclient.h | 1 - src/cdplusprotocol.cpp | 4 +- src/cdvframepacket.cpp | 31 +++- src/cdvframepacket.h | 6 +- src/cdvheaderpacket.cpp | 22 ++- src/cdvheaderpacket.h | 5 +- src/cdvlastframepacket.cpp | 4 +- src/cdvlastframepacket.h | 2 +- src/cgatekeeper.cpp | 2 + src/cpacketstream.cpp | 7 +- src/cpacketstream.h | 4 +- src/cprotocol.cpp | 14 ++ src/cprotocols.cpp | 28 ++-- src/creflector.cpp | 4 +- src/creflector.h | 2 +- src/ctranscoder.cpp | 8 +- src/cxlxclient.cpp | 3 + src/cxlxclient.h | 3 +- src/cxlxpeer.cpp | 6 +- src/cxlxprotocol.cpp | 47 +++++- src/cxlxprotocol.h | 3 + src/main.h | 28 ++-- 65 files changed, 1283 insertions(+), 485 deletions(-) create mode 100644 ambed/ccodec2interface.cpp create mode 100644 ambed/ccodec2interface.h create mode 100755 src/cdextraopenclient.cpp create mode 100644 src/cdextraopenclient.h create mode 100644 src/cdextraopenprotocol.cpp create mode 100644 src/cdextraopenprotocol.h 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 -----------------------------------------------