ambed single stack

pull/1/head
Tom Early 6 years ago
parent 004cea67a3
commit 1c9ee1b8c1

1
.gitignore vendored

@ -3,5 +3,4 @@
.vscode
xlxd
xrfd
ambed
main.h

@ -0,0 +1,50 @@
#copyright(C) 2020 by Thomas A. Early, N7TAE
# If you are going to change this path, you will
# need to update the systemd service script
BINDIR=/usr/local/bin
GCC=g++
# uncomment the next line to enable gdb debugging help
#DEBUG=true
CFLAGS=-W -MMD -MD -std=c++11
ifdef DEBUG
CFLAGS+=-ggdb3
endif
LDFLAGS=-pthread
SRCS=cagc.cpp cbuffer.cpp cfirfilter.cpp cip.cpp csignalprocessor.cpp cusb3003hrinterface.cpp cvocodecchannel.cpp cvoicepacket.cpp cambepacket.cpp ccallsign.cpp cfixedgain.cpp cpacket.cpp cstream.cpp cusb3000interface.cpp cusb3003interface.cpp cvocodecinterface.cpp main.cpp cambeserver.cpp ccontroller.cpp cftdidevicedescr.cpp cpacketqueue.cpp ctimepoint.cpp cusb3003df2etinterface.cpp cusb3xxxinterface.cpp cvocodecs.cpp cudpsocket.cpp
OBJS=$(SRCS:.cpp=.o)
DEPS=$(SRCS:.cpp=.d)
EXE=ambed
$(EXE) : $(OBJS)
$(GCC) $(LDFLAGS) $(OBJS) -lftd2xx -Wl,-rpath,/usr/local/lib -o $@
%.o : %.cpp
$(GCC) $(CFLAGS) -c $< -o $@
clean :
$(RM) $(EXE) *.o *.d
-include $(DEPS)
# The install and uninstall targets need to be run by root
install : $(EXE) $(EXE).service
cp $(EXE) $(BINDIR)
cp $(EXE).service /etc/systemd/system/
systemctl enable ambed
systemctl daemon-reload
systemctl start ambed
uninstall :
systemctl stop ambed
systemctl disable ambed
systemctl daemon-reload
rm -f /etc/systemd/system/ambed.service
rm -f $(BINDIR)/ambed
systemctl daemon-reload

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -29,97 +30,30 @@
#include "cambeserver.h"
////////////////////////////////////////////////////////////////////////////////////////
// globals
CAmbeServer g_AmbeServer;
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CAmbeServer::CAmbeServer()
{
m_bStopThreads = false;
m_pThread = NULL;
#ifdef DEBUG_DUMPFILE
m_DebugFile.open("/Users/jeanluc/Desktop/ambed.txt");
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CAmbeServer::~CAmbeServer()
{
m_bStopThreads = true;
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
}
#ifdef DEBUG_DUMPFILE
m_DebugFile.close();
#endif
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
bool CAmbeServer::Start(void)
{
bool ok = true;
// init interfaces & controller
std::cout << "Initializing vocodecs:" << std::endl;
ok &= g_Vocodecs.Init();
std::cout << std::endl;
if (! g_Vocodecs.Init())
return false;
std::cout << "Initializing controller" << std::endl;
ok &= m_Controller.Init();
std::cout << std::endl;
// if ok, start threads
if ( ok )
{
//
m_pThread = new std::thread(CAmbeServer::Thread, this);
}
// done
return ok;
if (! m_Controller.Init())
return false;
return true;
}
void CAmbeServer::Stop(void)
{
// stop controller
m_Controller.Close();
// stop & delete all threads
m_bStopThreads = true;
// stop & delete report threads
if ( m_pThread != NULL )
{
m_pThread->join();
delete m_pThread;
m_pThread = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CAmbeServer::Thread(CAmbeServer *This)
{
while ( !This->m_bStopThreads )
{
This->Task();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// task
void CAmbeServer::Task(void)
{
// and wait a bit
CTimePoint::TaskSleepFor(10000);
}

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -33,39 +34,25 @@
class CAmbeServer
{
public:
// constructors
CAmbeServer();
// destructor
virtual ~CAmbeServer();
// operation
bool Start(void);
void Stop(void);
// task
static void Thread(CAmbeServer *);
void Task(void);
// get
const CIp &GetListenIp(void) const { return m_Controller.GetListenIp(); }
const char *GetListenIp(void) const { return m_Controller.GetListenIp(); }
// set
void SetListenIp(const CIp &ip) { m_Controller.SetListenIp(ip); }
// operator
//bool operator ==(const CIp &) const;
//operator const char *() const;
void SetListenIp(const char *ip) { m_Controller.SetListenIp(ip); }
protected:
// objects
CController m_Controller;
// threads
bool m_bStopThreads;
std::thread *m_pThread;
public:
#ifdef DEBUG_DUMPFILE
std::ofstream m_DebugFile;

@ -1,200 +0,0 @@
//
// cbuffer.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// 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 "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CBuffer::CBuffer(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CBuffer::Set(uint8 *buffer, int len)
{
resize(len);
::memcpy(data(), buffer, len);
}
void CBuffer::Set(const char *sz)
{
resize(::strlen(sz)+1);
::strcpy((char *)data(), sz);
}
void CBuffer::Append(uint8 *buffer, int len)
{
int n = (int)size();
resize(n+len);
::memcpy(&(data()[n]), buffer, len);
}
void CBuffer::Append(uint8 ui, int len)
{
int n = (int)size();
resize(n+len);
::memset(&(data()[n]), ui, len);
}
void CBuffer::Append(uint8 ui)
{
int n = (int)size();
resize(n+sizeof(uint8));
::memcpy(&(data()[n]), &ui, sizeof(uint8));
}
void CBuffer::Append(uint16 ui)
{
int n = (int)size();
resize(n+sizeof(uint16));
::memcpy(&(data()[n]), &ui, sizeof(uint16));
}
void CBuffer::Append(uint32 ui)
{
int n = (int)size();
resize(n+sizeof(uint32));
::memcpy(&(data()[n]), &ui, sizeof(uint32));
}
void CBuffer::Append(const char *sz)
{
Append((uint8 *)sz, (int)strlen(sz));
Append((uint8)0x00);
}
void CBuffer::ReplaceAt(int i, uint8 ui)
{
if ( size() < (i+sizeof(uint8)) )
{
resize(i+sizeof(uint8));
}
*(uint8 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint16 ui)
{
if ( size() < (i+sizeof(uint16)) )
{
resize(i+sizeof(uint16));
}
*(uint16 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, uint32 ui)
{
if ( size() < (i+sizeof(uint32)) )
{
resize(i+sizeof(uint32));
}
*(uint32 *)(&(data()[i])) = ui;
}
void CBuffer::ReplaceAt(int i, const uint8 *ptr, int len)
{
if ( size() < (i+len) )
{
resize(i+len);
}
::memcpy(&(data()[i]), ptr, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// operation
int CBuffer::Compare(uint8 *buffer, int len) const
{
int result = -1;
if ( size() >= len )
{
result = ::memcmp(data(), buffer, len);
}
return result;
}
int CBuffer::Compare(uint8 *buffer, int off, int len) const
{
int result = -1;
if ( size() >= (off+len) )
{
result = ::memcmp(&(data()[off]), buffer, len);
}
return result;
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CBuffer::operator ==(const CBuffer &Buffer) const
{
if ( size() == Buffer.size() )
{
return (::memcmp((const char *)data(), (const char *)Buffer.data(), size()) == 0);
}
return false;
}
bool CBuffer::operator ==(const char *sz) const
{
if ( size() == ::strlen(sz) )
{
return (::memcmp((const char *)data(), sz, size()) == 0);
}
return false;
}
CBuffer::operator const char *() const
{
return (const char *)data();
}
////////////////////////////////////////////////////////////////////////////////////////
// debug
void CBuffer::DebugDump(std::ofstream &debugout)
{
for ( int i = 0; i < size(); i++ )
{
char sz[16];
sprintf(sz, "%02X", data()[i]);
debugout << sz;
if ( i == size()-1 )
{
debugout << std::endl;
}
else
{
debugout << ',';
}
}
}

@ -0,0 +1 @@
../src/cbuffer.cpp

@ -1,68 +0,0 @@
//
// cbuffer.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
// 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 cbuffer_h
#define cbuffer_h
////////////////////////////////////////////////////////////////////////////////////////
class CBuffer : public std::vector<uint8>
{
public:
// constructor
CBuffer() {};
CBuffer(uint8 *, int);
// destructor
virtual ~CBuffer() {};
// set
void Set(uint8 *, int);
void Set(const char *);
void Append(uint8 *, int);
void Append(uint8, int);
void Append(uint8);
void Append(uint16);
void Append(uint32);
void Append(const char *);
void ReplaceAt(int, uint8);
void ReplaceAt(int, uint16);
void ReplaceAt(int, uint32);
void ReplaceAt(int, const uint8 *, int);
// operation
int Compare(uint8 *, int) const;
int Compare(uint8 *, int, int) const;
// operator
bool operator ==(const CBuffer &) const;
bool operator ==(const char *) const;
operator const char *() const;
// debug
void DebugDump(std::ofstream &);
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cbuffer_h */

@ -0,0 +1 @@
../src/cbuffer.h

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -35,7 +36,6 @@ CController::CController()
{
m_bStopThread = false;
m_pThread = NULL;
m_Ip = CIp("127.0.0.1");
m_uiLastStreamId = 0;
}
@ -46,18 +46,18 @@ CController::~CController()
{
// close socket
m_Socket.Close();
// close all streams
m_Mutex.lock();
{
for ( int i = 0; i < m_Streams.size(); i++ )
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); it++ )
{
delete m_Streams[i];
delete *it;
}
m_Streams.clear();
}
m_Mutex.unlock();
m_bStopThread = true;
if ( m_pThread != NULL )
@ -72,24 +72,23 @@ CController::~CController()
bool CController::Init(void)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// create our socket
ok = m_Socket.Open(m_Ip, TRANSCODER_PORT);
if ( ok )
{
// start thread;
m_pThread = new std::thread(CController::Thread, this);
}
else
CIp ip(strchr(straddress, ':') ? AF_INET6 : AF_INET, TRANSCODER_PORT, straddress);
if (! ip.IsSet()) {
std::cerr << "IP initialization failed for " << straddress << std::endl;
return false;
}
if (! m_Socket.Open(ip))
{
std::cout << "Error opening socket on port UDP" << TRANSCODER_PORT << " on ip " << m_Ip << std::endl;
std::cout << "Error opening socket on port UDP" << TRANSCODER_PORT << " on ip " << ip.GetAddress() << std::endl;
return false;
}
// done
// start thread;
m_pThread = new std::thread(CController::Thread, this);
return true;
}
@ -127,18 +126,18 @@ void CController::Task(void)
uint8 CodecOut;
uint16 StreamId;
CStream *Stream;
// anything coming in from codec client ?
if ( m_Socket.Receive(&Buffer, &Ip, 20) != -1 )
if ( m_Socket.Receive(Buffer, Ip, 20) != -1 )
{
// crack packet
if ( IsValidOpenstreamPacket(Buffer, &Callsign, &CodecIn, &CodecOut) )
{
std::cout << "Stream Open from " << Callsign << std::endl;
// try create the stream
Stream = OpenStream(Callsign, Ip, CodecIn, CodecOut);
// send back details
if ( Stream != NULL )
{
@ -154,8 +153,8 @@ void CController::Task(void)
{
// close the stream
CloseStream(StreamId);
std::cout << "Stream " << (int)StreamId << " closed" << std::endl;
std::cout << "Stream " << (int)StreamId << " closed" << std::endl;
}
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
{
@ -165,38 +164,24 @@ void CController::Task(void)
m_Socket.Send(Buffer, Ip);
}
}
// HandleTimout/keepalive
bool timeout;
do
{
// init loop stuffs
timeout = false;
CStream *stream = NULL;
// any inactive streams?
Lock();
{
for ( int i = 0; (i < m_Streams.size()) && !timeout; i++ )
{
if ( !(m_Streams[i]->IsActive()) )
{
timeout = true;
stream = m_Streams[i];
std::cout << "Stream " << (int)m_Streams[i]->GetId() << " activity timeout " << std::endl;
}
}
}
Unlock();
// if any streams timeout, close it
// this cannot be done in above loop as it suppress it from array
if ( timeout )
{
CloseStream(stream);
}
} while (timeout);
// any inactive streams?
Lock();
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); )
{
if ( !(*it)->IsActive() )
{
std::cout << "Stream " << (*it)->GetId() << " activity timeout " << std::endl;
(*it)->Close();
delete *it;
it = m_Streams.erase(it);
}
else
{
it++;
}
}
Unlock();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -205,7 +190,7 @@ void CController::Task(void)
CStream *CController::OpenStream(const CCallsign &Callsign, const CIp &Ip, uint8 CodecIn, uint8 CodecOut)
{
CStream *stream = NULL;
// create a new stream
m_uiLastStreamId = (m_uiLastStreamId + 1);
m_uiLastStreamId = (m_uiLastStreamId == NB_MAX_STREAMS+1) ? 1 : m_uiLastStreamId;
@ -223,56 +208,50 @@ CStream *CController::OpenStream(const CCallsign &Callsign, const CIp &Ip, uint8
delete stream;
stream = NULL;
}
// done
return stream;
}
void CController::CloseStream(CStream *stream)
{
Lock();
{
// look for the stream
bool found = false;
for ( int i = 0; (i < m_Streams.size()) && !found; i++ )
{
// compare object pointers
if ( (m_Streams[i]) == stream )
{
// close it
m_Streams[i]->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete m_Streams[i];
m_Streams.erase(m_Streams.begin()+i);
found = true;
}
}
}
Unlock();
Lock();
// look for the stream
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); it++ )
{
// compare object pointers
if ( *it == stream )
{
// close it
(*it)->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete *it;
m_Streams.erase(it);
break;
}
}
Unlock();
}
void CController::CloseStream(uint16 StreamId)
{
Lock();
{
// look for the stream
bool found = false;
for ( int i = 0; (i < m_Streams.size()) && !found; i++ )
{
// compare object pointers
if ( (m_Streams[i]->GetId()) == StreamId )
{
// close it
m_Streams[i]->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete m_Streams[i];
m_Streams.erase(m_Streams.begin()+i);
found = true;
}
}
}
// look for the stream
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); it++ )
{
// compare object pointers
if ( (*it)->GetId() == StreamId )
{
// close it
(*it)->Close();
// remove it
//std::cout << "Stream " << m_Streams[i]->GetId() << " removed" << std::endl;
delete *it;
m_Streams.erase(it);
break;
}
}
Unlock();
}
@ -282,7 +261,7 @@ void CController::CloseStream(uint16 StreamId)
bool CController::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *Callsign)
{
uint8 tag[] = { 'A','M','B','E','D','P','I','N','G' };
bool valid = false;
if ( (Buffer.size() == 17) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
@ -296,7 +275,7 @@ bool CController::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *Calls
bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Callsign, uint8 *CodecIn, uint8 *CodecOut)
{
uint8 tag[] = { 'A','M','B','E','D','O','S' };
bool valid = false;
if ( (Buffer.size() == 17) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
@ -304,7 +283,7 @@ bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Call
Callsign->SetCallsign(&(Buffer.data()[7]), 8);
*CodecIn = Buffer.data()[15];
*CodecOut = Buffer.data()[16];
// valid ?
valid = Callsign->IsValid() && IsValidCodecIn(*CodecIn) && IsValidCodecOut(*CodecOut);
}
@ -314,7 +293,7 @@ bool CController::IsValidOpenstreamPacket(const CBuffer &Buffer, CCallsign *Call
bool CController::IsValidClosestreamPacket(const CBuffer &Buffer, uint16 *StreamId)
{
uint8 tag[] = { 'A','M','B','E','D','C','S' };
bool valid = false;
if ( /*(Buffer.size() == 16) &&*/ (Buffer.Compare(tag, sizeof(tag)) == 0) )
{
@ -331,14 +310,14 @@ bool CController::IsValidClosestreamPacket(const CBuffer &Buffer, uint16 *Stream
void CController::EncodeKeepAlivePacket(CBuffer *Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','P','O','N','G' };
Buffer->Set(tag, sizeof(tag));
}
void CController::EncodeStreamDescrPacket(CBuffer *Buffer, const CStream &Stream)
{
uint8 tag[] = { 'A','M','B','E','D','S','T','D' };
Buffer->Set(tag, sizeof(tag));
// id
Buffer->Append((uint16)Stream.GetId());
@ -353,7 +332,7 @@ void CController::EncodeStreamDescrPacket(CBuffer *Buffer, const CStream &Stream
void CController::EncodeNoStreamAvailablePacket(CBuffer *Buffer)
{
uint8 tag[] = { 'A','M','B','E','D','B','U','S','Y' };
Buffer->Set(tag, sizeof(tag));
}
@ -370,4 +349,3 @@ bool CController::IsValidCodecOut(uint8 codec)
{
return ((codec == CODEC_AMBEPLUS) || (codec == CODEC_AMBE2PLUS) );
}

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -36,10 +37,10 @@ class CController
public:
// constructors
CController();
// destructor
virtual ~CController();
// initialization
bool Init(void);
void Close(void);
@ -47,28 +48,28 @@ public:
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// get
const CIp &GetListenIp(void) const { return (const CIp &)m_Ip; }
const CIp &GetListenIp(void) const { return straddress; }
// set
void SetListenIp(const CIp &ip) { m_Ip = ip; }
void SetListenIp(const char *str) { straddress = str; }
// streams management
CStream *OpenStream(const CCallsign &, const CIp &, uint8, uint8);
void CloseStream(CStream *);
void CloseStream(uint16);
// task
static void Thread(CController *);
void Task(void);
protected:
// packet decoding helpers
// packet decoding helpers
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *);
bool IsValidOpenstreamPacket(const CBuffer &, CCallsign *, uint8 *, uint8 *);
bool IsValidClosestreamPacket(const CBuffer &, uint16 *);
// packet encoding helpers
void EncodeKeepAlivePacket(CBuffer *);
void EncodeStreamDescrPacket(CBuffer *, const CStream &);
@ -77,21 +78,21 @@ protected:
// codec helpers
bool IsValidCodecIn(uint8);
bool IsValidCodecOut(uint8);
protected:
// control socket
CIp m_Ip;
CUdpSocket m_Socket;
const char *straddress;
CUdpSocket m_Socket;
// streams
uint16 m_uiLastStreamId;
std::mutex m_Mutex;
std::vector<CStream *> m_Streams;
uint16 m_uiLastStreamId;
std::mutex m_Mutex;
std::list<CStream *> m_Streams;
// thread
bool m_bStopThread;
std::thread *m_pThread;
bool m_bStopThread;
std::thread *m_pThread;
};
////////////////////////////////////////////////////////////////////////////////////////

@ -1,91 +0,0 @@
//
// cip.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// 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 "cip.h"
#include <netdb.h>
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CIp::CIp()
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
}
CIp::CIp(const char *sz)
{
::memset(&m_Addr, 0, sizeof(m_Addr));
m_Addr.sin_family = AF_INET;
// try xxx.xxx.xxx.xxxx first
m_Addr.sin_addr.s_addr = inet_addr(sz);
if ( m_Addr.sin_addr.s_addr == INADDR_NONE )
{
// otherwise try to resolve via dns
hostent *record = gethostbyname(sz);
if( record != NULL )
{
m_Addr.sin_addr.s_addr = ((in_addr * )record->h_addr)->s_addr;
}
}
}
CIp::CIp(const struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
CIp::CIp(const CIp &ip)
{
::memcpy(&m_Addr, &ip.m_Addr, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CIp::SetSockAddr(struct sockaddr_in *sa)
{
::memcpy(&m_Addr, sa, sizeof(m_Addr));
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CIp::operator ==(const CIp &ip) const
{
return ( (ip.m_Addr.sin_family == m_Addr.sin_family) &&
(ip.m_Addr.sin_addr.s_addr == m_Addr.sin_addr.s_addr) &&
(ip.m_Addr.sin_port == m_Addr.sin_port)) ;
}
CIp::operator const char *() const
{
return ::inet_ntoa(m_Addr.sin_addr);
}

@ -0,0 +1 @@
../src/cip.cpp

@ -1,59 +0,0 @@
//
// cip.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// 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 cip_h
#define cip_h
////////////////////////////////////////////////////////////////////////////////////////
// class
class CIp
{
public:
// constructors
CIp();
//CIp(uint8, uint8, uint8, uint8);
CIp(const struct sockaddr_in *);
CIp(const char *);
CIp(const CIp &);
// destructor
virtual ~CIp() {};
// sockaddr
void SetSockAddr(struct sockaddr_in *);
struct sockaddr_in *GetSockAddr(void) { return &m_Addr; }
// operator
bool operator ==(const CIp &) const;
operator const char *() const;
protected:
// data
struct sockaddr_in m_Addr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cip_h */

@ -0,0 +1 @@
../src/cip.h

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 15/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -79,7 +80,7 @@ CStream::~CStream()
delete m_pThread;
m_pThread = NULL;
}
// then close everything
m_Socket.Close();
if ( m_VocodecChannel != NULL )
@ -93,45 +94,48 @@ CStream::~CStream()
bool CStream::Init(uint16 uiPort)
{
bool ok;
// reset stop flag
m_bStopThread = false;
// create our socket
ok = m_Socket.Open(g_AmbeServer.GetListenIp(), uiPort);
if ( ok )
{
// open the vocodecchannel
ok &= ((m_VocodecChannel = g_Vocodecs.OpenChannel(m_uiCodecIn, m_uiCodecOut)) != NULL);
if ( ok )
{
// store port
m_uiPort = uiPort;
// start thread;
m_pThread = new std::thread(CStream::Thread, this);
// init timeout system
m_LastActivity.Now();
m_iTotalPackets = 0;
m_iLostPackets = 0;
}
else
{
std::cout << "Error opening stream : no suitable channel available" << std::endl;
}
}
else
{
std::cout << "Error opening socket on port UDP" << uiPort << " on ip " << m_Ip << std::endl;
}
auto s = g_AmbeServer.GetListenIp();
CIp ip(strchr(s, ':') ? AF_INET6 : AF_INET, uiPort, s);
if (! ip.IsSet())
{
std::cerr << "Could not initialize ip address " << s << std::endl;
return false;
}
if (! m_Socket.Open(ip))
{
std::cout << "Error opening stream stream socket on " << ip << std::endl;
return false;
}
// open the vocodecchannel
m_VocodecChannel = g_Vocodecs.OpenChannel(m_uiCodecIn, m_uiCodecOut);
if (NULL == m_VocodecChannel)
{
std::cerr << "Could not open Vocodec Channel" << std::endl;
m_Socket.Close();
return false;
}
// store port
m_uiPort = uiPort;
// start thread;
m_pThread = new std::thread(CStream::Thread, this);
// init timeout system
m_LastActivity.Now();
m_iTotalPackets = 0;
m_iLostPackets = 0;
// done
return ok;
return true;
}
void CStream::Close(void)
@ -151,8 +155,8 @@ void CStream::Close(void)
{
m_VocodecChannel->Close();
}
// report
std::cout << m_iLostPackets << " of " << m_iTotalPackets << " packets lost" << std::endl;
}
@ -179,9 +183,9 @@ void CStream::Task(void)
uint8 Ambe[AMBE_FRAME_SIZE];
CAmbePacket *packet;
CPacketQueue *queue;
// anything coming in from codec client ?
if ( m_Socket.Receive(&Buffer, &Ip, 1) != -1 )
if ( m_Socket.Receive(Buffer, Ip, 1) )
{
// crack packet
if ( IsValidDvFramePacket(Buffer, &uiPid, Ambe) )
@ -189,7 +193,7 @@ void CStream::Task(void)
// transcode AMBE here
m_LastActivity.Now();
m_iTotalPackets++;
// post packet to VocoderChannel
packet = new CAmbePacket(uiPid, m_uiCodecIn, Ambe);
queue = m_VocodecChannel->GetPacketQueueIn();
@ -197,7 +201,7 @@ void CStream::Task(void)
m_VocodecChannel->ReleasePacketQueueIn();
}
}
// anything in our queue ?
queue = m_VocodecChannel->GetPacketQueueOut();
while ( !queue->empty() )
@ -220,7 +224,7 @@ void CStream::Task(void)
bool CStream::IsValidDvFramePacket(const CBuffer &Buffer, uint8 *pid, uint8 *ambe)
{
bool valid = false;
if ( Buffer.size() == 11 )
{
uint8 codec = Buffer.data()[0];
@ -228,7 +232,7 @@ bool CStream::IsValidDvFramePacket(const CBuffer &Buffer, uint8 *pid, uint8 *amb
::memcpy(ambe, &(Buffer.data()[2]), 9);
valid = (codec == GetCodecIn());
}
return valid;
}
@ -242,4 +246,3 @@ void CStream::EncodeDvFramePacket(CBuffer *Buffer, uint8 Pid, uint8 *Ambe)
Buffer->Append((uint8)Pid);
Buffer->Append(Ambe, 9);
}

@ -1,172 +0,0 @@
//
// cudpsocket.cpp
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// 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 "cudpsocket.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CUdpSocket::CUdpSocket()
{
m_Socket = -1;
}
////////////////////////////////////////////////////////////////////////////////////////
// destructor
CUdpSocket::~CUdpSocket()
{
if ( m_Socket != -1 )
{
Close();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// open & close
bool CUdpSocket::Open(const CIp &ListenIp, uint16 uiPort)
{
bool open = false;
// create socket
m_Socket = socket(PF_INET,SOCK_DGRAM,0);
if ( m_Socket != -1 )
{
// initialize sockaddr struct
::memset(&m_SocketAddr, 0, sizeof(struct sockaddr_in));
m_SocketAddr.sin_family = AF_INET;
m_SocketAddr.sin_port = htons(uiPort);
m_SocketAddr.sin_addr.s_addr = inet_addr(ListenIp);
if ( bind(m_Socket, (struct sockaddr *)&m_SocketAddr, sizeof(struct sockaddr_in)) == 0 )
{
fcntl(m_Socket, F_SETFL, O_NONBLOCK);
open = true;
}
else
{
close(m_Socket);
m_Socket = -1;
}
}
// done
return open;
}
void CUdpSocket::Close(void)
{
if ( m_Socket != -1 )
{
close(m_Socket);
m_Socket = -1;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// read
int CUdpSocket::Receive(CBuffer *Buffer, CIp *Ip, int timeout)
{
struct sockaddr_in Sin;
fd_set FdSet;
unsigned int uiFromLen = sizeof(struct sockaddr_in);
int iRecvLen = -1;
struct timeval tv;
// socket valid ?
if ( m_Socket != -1 )
{
// control socket
FD_ZERO(&FdSet);
FD_SET(m_Socket, &FdSet);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
select(m_Socket + 1, &FdSet, 0, 0, &tv);
// allocate buffer
Buffer->resize(UDP_BUFFER_LENMAX);
// read
iRecvLen = (int)recvfrom(m_Socket,
(void *)Buffer->data(), UDP_BUFFER_LENMAX,
0, (struct sockaddr *)&Sin, &uiFromLen);
// handle
if ( iRecvLen != -1 )
{
// adjust buffer size
Buffer->resize(iRecvLen);
// get IP
Ip->SetSockAddr(&Sin);
}
}
// done
return iRecvLen;
}
////////////////////////////////////////////////////////////////////////////////////////
// write
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip)
{
CIp temp(Ip);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const CBuffer &Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer.data(), Buffer.size(),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}
int CUdpSocket::Send(const char *Buffer, const CIp &Ip, uint16 destport)
{
CIp temp(Ip);
temp.GetSockAddr()->sin_port = htons(destport);
return (int)::sendto(m_Socket,
(void *)Buffer, ::strlen(Buffer),
0, (struct sockaddr *)temp.GetSockAddr(), sizeof(struct sockaddr_in));
}

@ -0,0 +1 @@
../src/cudpsocket.cpp

@ -1,78 +0,0 @@
//
// cudpsocket.h
// xlxd
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
// 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 cudpsocket_h
#define cudpsocket_h
#include <sys/types.h>
//#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include "cip.h"
#include "cbuffer.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define UDP_BUFFER_LENMAX 1024
////////////////////////////////////////////////////////////////////////////////////////
// class
class CUdpSocket
{
public:
// constructor
CUdpSocket();
// destructor
~CUdpSocket();
// open & close
bool Open(const CIp &, uint16);
void Close(void);
int GetSocket(void) { return m_Socket; }
// read
int Receive(CBuffer *, CIp *, int);
// write
int Send(const CBuffer &, const CIp &);
int Send(const CBuffer &, const CIp &, uint16);
int Send(const char *, const CIp &);
int Send(const char *, const CIp &, uint16);
protected:
// data
int m_Socket;
struct sockaddr_in m_SocketAddr;
};
////////////////////////////////////////////////////////////////////////////////////////
#endif /* cudpsocket_h */

@ -0,0 +1 @@
../src/cudpsocket.h

@ -4,6 +4,7 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// Copyright © 2020 Thomas A. Early, N7TAE
//
// ----------------------------------------------------------------------------
// This file is part of ambed.
@ -26,65 +27,15 @@
#include "ctimepoint.h"
#include "cambeserver.h"
#include "syslog.h"
#include <sys/stat.h>
////////////////////////////////////////////////////////////////////////////////////////
// global objects
////////////////////////////////////////////////////////////////////////////////////////
// function declaration
int main(int argc, const char * argv[])
{
#ifdef RUN_AS_DAEMON
// redirect cout, cerr and clog to syslog
syslog::redirect cout_redir(std::cout);
syslog::redirect cerr_redir(std::cerr);
syslog::redirect clog_redir(std::clog);
//Fork the Parent Process
pid_t pid, sid;
pid = ::fork();
//pid = ::vfork();
if ( pid < 0 )
{
exit(EXIT_FAILURE);
}
// We got a good pid, Close the Parent Process
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
// Change File Mask
::umask(0);
//Create a new Signature Id for our child
sid = ::setsid();
if (sid < 0)
{
exit(EXIT_FAILURE);
}
// Change Directory
// If we cant find the directory we exit with failure.
if ( (::chdir("/")) < 0)
{
exit(EXIT_FAILURE);
}
// Close Standard File Descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
#endif
// check arguments
if ( argc != 2 )
{
@ -92,40 +43,25 @@ int main(int argc, const char * argv[])
std::cout << "example: ambed 192.168.178.212" << std::endl;
return 1;
}
// initialize ambeserver
g_AmbeServer.SetListenIp(CIp(argv[1]));
g_AmbeServer.SetListenIp(argv[1]);
// and let it run
std::cout << "Starting AMBEd " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
if ( !g_AmbeServer.Start() )
if ( ! g_AmbeServer.Start() )
{
std::cout << "Error starting AMBEd" << std::endl;
exit(EXIT_FAILURE);
return EXIT_FAILURE;
}
std::cout << "AMBEd started and listening on " << g_AmbeServer.GetListenIp() << std::endl;
#ifdef RUN_AS_DAEMON
// run forever
while ( true )
{
// sleep 60 seconds
CTimePoint::TaskSleepFor(60000);
}
#else
// wait any key
for (;;)
{
// sleep 60 seconds
CTimePoint::TaskSleepFor(60000);
//std::cin.get();
}
#endif
pause(); // wait for any signal
// and wait for end
g_AmbeServer.Stop();
std::cout << "AMBEd stopped" << std::endl;
// done
exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
}

@ -27,6 +27,7 @@
#include <vector>
#include <array>
#include <list>
#include <map>
#include <queue>
#include <chrono>
@ -102,7 +103,7 @@ typedef unsigned int uint;
#define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF))
////////////////////////////////////////////////////////////////////////////////////////
// FIR Filter coefficients computed to be the closest to the recommended filter in
// FIR Filter coefficients computed to be the closest to the recommended filter in
// Documentation
//
// Following GNU Octave script was used
@ -143,6 +144,6 @@ extern CAmbeServer g_AmbeServer;
class CVocodecs;
extern CVocodecs g_Vocodecs;
////////////////////////////////////////////////////////////////////////////////////////
#endif /* main_h */

@ -1,22 +0,0 @@
CC=g++
CFLAGS=-c -std=c++11 -pthread
LDFLAGS=-std=c++11 -pthread
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=ambed
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -lftd2xx -Wl,-rpath,/usr/local/lib -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
clean:
$(RM) $(EXECUTABLE) *.o
install:
mkdir -p /ambed
cp $(EXECUTABLE) /ambed/
cp ./run /ambed/

@ -1,6 +0,0 @@
#!/bin/bash
# start ambed server
sudo rmmod ftdi_sio
sudo rmmod usbserial
sudo /ambed/ambed 127.0.0.1 &

@ -1,96 +0,0 @@
/*************************************************************************
** Copyright (C) 2014 Jan Pedersen <jp@jp-embedded.com>
**
** This program 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.
**
** This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************/
#ifndef __syslog
#define __syslog
#include <iostream>
#include <streambuf>
#include <string>
namespace csyslog {
#include <syslog.h>
}
namespace syslog
{
struct level {
enum pri {
emerg = LOG_EMERG, // A panic condition
alert = LOG_ALERT, // A condition that should be corrected
critical= LOG_CRIT, // Critical condition, e.g, hard device error
error = LOG_ERR, // Errors
warning = LOG_WARNING, // Warning messages
notice = LOG_NOTICE, // Possibly be handled specially
info = LOG_INFO, // Informational
debug = LOG_DEBUG // For debugging program
};
};
class streambuf : public std::streambuf
{
std::string _buf;
int _level;
public:
streambuf() : _level(level::debug) { }
void level(int level) { _level = level; }
protected:
int sync()
{
if (_buf.size()) {
csyslog::syslog(_level, "%s", _buf.c_str());
_buf.erase();
}
return 0;
}
int_type overflow(int_type c)
{
if(c == traits_type::eof()) sync();
else _buf += static_cast<char>(c);
return c;
}
};
class ostream : public std::ostream
{
streambuf _logbuf;
public:
ostream() : std::ostream(&_logbuf) {}
ostream& operator<<(const level::pri lev) { _logbuf.level(lev); return *this; }
};
class redirect
{
ostream dst;
std::ostream &src;
std::streambuf * const sbuf;
public:
redirect(std::ostream & src) : src(src), sbuf(src.rdbuf(dst.rdbuf())) { dst << (&src == &std::cout ? level::info : level::error); }
~redirect() { src.rdbuf(sbuf); }
};
}
#endif

@ -25,7 +25,6 @@
#include <string.h>
#include "main.h"
#include "creflector.h"
#include "cudpsocket.h"

Loading…
Cancel
Save

Powered by TurnKey Linux.