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 -----------------------------------------------