pull/118/merge
Antony Chazapis 7 years ago committed by GitHub
commit 1fbe437b2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "main.h"
#include <string.h>
#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);
}

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#ifndef ccodec2interface_h
#define ccodec2interface_h
#include "cvocodecinterface.h"
#include <codec2/codec2.h>
////////////////////////////////////////////////////////////////////////////////////////
// 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 */

@ -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)));
}

@ -76,7 +76,7 @@ protected:
// codec helpers
bool IsValidCodecIn(uint8);
bool IsValidCodecOut(uint8);
bool IsValidCodecsOut(uint8);
protected:
// control socket

@ -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<CVocodecChannel *>*channels)
{
CVocodecChannel *ChannelA = new CVocodecChannel(InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, InterfaceCodec2, ChannelCodec2, CODECGAIN_AMBEPLUS);
CVocodecChannel *ChannelB = new CVocodecChannel(InterfaceAmbePlus, ChannelAmbePlus, InterfaceAmbe, ChannelAmbe, InterfaceCodec2, ChannelCodec2, CODECGAIN_AMBE2PLUS);
CVocodecChannel *ChannelC = new CVocodecChannel(InterfaceCodec2, ChannelCodec2, InterfaceAmbe, ChannelAmbe, InterfaceAmbePlus, ChannelAmbePlus, CODECGAIN_CODEC2);
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
//
@ -215,68 +235,30 @@ int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vector<CVocode
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) )
{
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);
Usb3003C->Init(CODEC_AMBEPLUS) && Usb3003D->Init(CODEC_AMBE2PLUS) &&
Codec2A->Init() && Codec2B->Init() &&
Codec2C->Init() && Codec2D->Init() &&
Codec2E->Init() && Codec2F->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
CreateChannelGroup(Usb3003C, 0, Usb3003C, 1, Codec2D, 0, channels);
CreateChannelGroup(Usb3003D, 0, Usb3003D, 1, Codec2E, 0, channels);
CreateChannelGroup(Usb3003C, 2, Usb3003D, 2, Codec2F, 0, channels);
// done
nStreams = 12;
}
nStreams = 18;
}
else
{
@ -285,6 +267,12 @@ int CFtdiDeviceDescr::CreateUsb3012(CFtdiDeviceDescr *descr, std::vector<CVocode
delete Usb3003B;
delete Usb3003C;
delete Usb3003D;
delete Codec2A;
delete Codec2B;
delete Codec2C;
delete Codec2D;
delete Codec2E;
delete Codec2F;
}
// done
@ -308,47 +296,30 @@ int CFtdiDeviceDescr::CreateUsb3006(CFtdiDeviceDescr *descr, std::vector<CVocode
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) )
{
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);
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) &&
Codec2A->Init() && Codec2B->Init() && Codec2C->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
// done
nStreams = 6;
}
nStreams = 9;
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
delete Codec2A;
delete Codec2B;
delete Codec2C;
}
// done
@ -373,28 +344,22 @@ int CFtdiDeviceDescr::CreateUsb3003(CFtdiDeviceDescr *descr, std::vector<CVocode
// create the interfaces for the 3003 chip
CUsb3003Interface *Usb3003 = InstantiateUsb3003(descr);
// create the virtual interfaces for Codec 2
CCodec2Interface *Codec2 = new CCodec2Interface();
// init the interface
if ( (Usb3003 != NULL) && Usb3003->Init(CODEC_NONE) )
{
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);
if ( (Usb3003 != NULL) && Usb3003->Init(CODEC_NONE) && Codec2->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003, 0, Usb3003, 1, Codec2, 0, channels);
// done
nStreams = 2;
}
nStreams = 3;
}
else
{
// cleanup
delete Usb3003;
delete Codec2;
}
// done
@ -409,31 +374,23 @@ int CFtdiDeviceDescr::CreatePair(CUsb3000Interface *Usb3000A, CUsb3000Interface
{
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) )
{
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);
if ( Usb3000A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) && Codec2->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3000A, 0, Usb3000B, 0, Codec2, 0, channels);
// done
nStreams = 2;
}
nStreams = 3;
}
else
{
// cleanup
delete Usb3000A;
delete Usb3000B;
delete Codec2;
}
// done
@ -448,47 +405,30 @@ int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3003Interface
{
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) )
{
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);
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3003B->Init(CODEC_AMBE2PLUS) &&
Codec2A->Init() && Codec2B->Init() && Codec2C->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003B, 0, Usb3003B, 1, Codec2B, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3003B, 2, Codec2C, 0, channels);
// done
nStreams = 6;
}
nStreams = 9;
}
else
{
// cleanup
delete Usb3003A;
delete Usb3003B;
delete Codec2A;
delete Codec2B;
delete Codec2C;
}
// done
@ -502,39 +442,27 @@ int CFtdiDeviceDescr::CreatePair(CUsb3003Interface *Usb3003A, CUsb3000Interface
{
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) )
{
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);
if ( Usb3003A->Init(CODEC_AMBEPLUS) && Usb3000B->Init(CODEC_AMBE2PLUS) &&
Codec2A->Init() && Codec2B->Init() )
{
// create the channels in groups
CreateChannelGroup(Usb3003A, 0, Usb3003A, 1, Codec2A, 0, channels);
CreateChannelGroup(Usb3003A, 2, Usb3000B, 0, Codec2B, 0, channels);
// done
nStreams = 4;
}
nStreams = 6;
}
else
{
// cleanup
delete Usb3003A;
delete Usb3000B;
delete Codec2A;
delete Codec2B;
}
// done

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

@ -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();
}

@ -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;
};
////////////////////////////////////////////////////////////////////////////////////////

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

@ -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 *);

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

@ -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 *);

@ -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);
if ( Channel->IsInterfaceOut1(this) )
{
Queue = Channel->GetPacketQueueOut1();
Queue->push(clone);
Channel->ReleasePacketQueueOut1();
}
else if ( Channel->IsInterfaceOut2(this) )
{
Queue = Channel->GetPacketQueueOut2();
Queue->push(clone);
Channel->ReleasePacketQueueOut();
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() )

@ -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_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();
}

@ -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; }
@ -77,17 +88,24 @@ protected:
// status
bool m_bOpen;
// array of grouped channels
std::vector<CVocodecChannel *> m_GroupChannels;
// connected interfaces
CVocodecInterface *m_InterfaceIn;
int m_iChannelIn;
CVocodecInterface *m_InterfaceOut;
int m_iChannelOut;
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_QueuePacketOut1;
CPacketQueue m_QueuePacketOut2;
// voice queues
CPacketQueue m_QueueVoice1;
CPacketQueue m_QueueVoice2;
// settings
int m_iSpeechGain;

@ -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;
}

@ -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,8 +65,10 @@ public:
virtual bool operator ==(const CVocodecInterface &) const { return false; }
protected:
// array of channels
std::vector<CVocodecChannel *> m_Channels;
// open channel state
std::mutex m_MutexChannels;
std::vector<CVocodecChannel *> m_ChannelIn;
std::vector<CVocodecChannel *> m_ChannelOut;
// thread
bool m_bStopThread;

@ -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();
}

@ -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 )
{

@ -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_AMBE2PLUS +10 // in dB
#define CODECGAIN_CODEC2 0 // in dB
// Timeouts -----------------------------------------------------
#define STREAM_ACTIVITY_TIMEOUT 3 // in seconds

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

@ -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;
}

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

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

@ -32,10 +32,10 @@ int main(int argc, const char * argv[])
std::vector<CCodecStream *> 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++ )
{
@ -62,6 +63,12 @@ int main(int argc, const char * argv[])
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();

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

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

@ -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; }

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

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

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

@ -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));

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

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#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)
{}

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#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 */

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "main.h"
#include <string.h>
#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;
}

@ -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 <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#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 */

@ -24,8 +24,8 @@
#include "main.h"
#include <string.h>
#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());

@ -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);

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

@ -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);

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

@ -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);

@ -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; }

@ -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());

@ -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) );

@ -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];

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

@ -75,11 +75,14 @@ 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; }
const CCallsign &GetRpt1Callsign(void) const { return m_csRPT1; }

@ -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)
{
}

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

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

@ -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;
}

@ -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;
};

@ -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);

@ -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();

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

@ -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 *);

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

@ -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;
}

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

@ -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;
}

@ -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));

@ -52,6 +52,9 @@ public:
// task
void Task(void);
// identity
int GetProtocol(void) const { return PROTOCOL_XLX; }
protected:
// queue helper
void HandleQueue(void);

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

Loading…
Cancel
Save

Powered by TurnKey Linux.