Compare commits

...

3 commits

Author SHA1 Message Date
narspt 0911129442
Merge 2225f4e17f into 129f1257b4 2023-12-12 13:33:31 +01:00
narspt 2225f4e17f copy xlxd.transcoder on make install 2023-12-03 19:02:34 +00:00
narspt 914de977a0 implement transcoder options and auto mode 2022-06-05 02:14:36 +01:00
12 changed files with 227 additions and 14 deletions

19
config/xlxd.transcoder Normal file
View file

@ -0,0 +1,19 @@
#########################################################################################
# XLXD transcoder options file
#
# One line per entry, each entry specifies a transcoder option.
#
# Valid options (case-sensitive):
# Address <ip> - Ip address of the ambed server used for transcoding.
# ModulesOn <modules> - A string with all modules which transcoding should be enabled,
# "*" means all modules.
# ModulesAuto <modules> - A string with all modules which transcoding should be enabled
# in automatic mode (transcoding will get enabled only if there
# are clients linked on the module with different codecs),
# "*" means all modules. ModulesOn supersedes ModulesAuto.
#
#########################################################################################
Address 127.0.0.1
ModulesOn ABCD
ModulesAuto *

View file

@ -23,6 +23,7 @@ $PageOptions['PageRefreshActive'] = true; // Activate automa
$PageOptions['PageRefreshDelay'] = '10000'; // Page refresh time in miliseconds
$PageOptions['NumberOfModules'] = 10; // Number of Modules enabled on reflector
$PageOptions['TranscoderFile'] = '/xlxd/xlxd.transcoder'; // Path to transcoder file
$PageOptions['RepeatersPage'] = array();
$PageOptions['RepeatersPage']['LimitTo'] = 99; // Number of Repeaters to show

View file

@ -1,8 +1,9 @@
<table class="listingtable">
<tr>
<th width="80" rowspan="2">Module</th>
<th width="75" rowspan="2">Module</th>
<th width="130" rowspan="2">Name</th>
<th width="65" rowspan="2">Users</th>
<th width="60" rowspan="2">Users</th>
<th width="60" rowspan="2">Trans<br />coder</th>
<th colspan="2">DPlus</th>
<th colspan="2">DExtra</th>
<th colspan="2">DCS</th>
@ -11,17 +12,35 @@
</tr>
<tr>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
<th width="85">DTMF</th>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
<th width="85">DTMF</th>
<th width="100">URCALL</th>
<th width="100">DTMF</th>
<th width="85">DTMF</th>
</tr>
<?php
$ReflectorNumber = substr($Reflector->GetReflectorName(), 3, 3);
$NumberOfModules = isset($PageOptions['NumberOfModules']) ? min(max($PageOptions['NumberOfModules'],0),26) : 26;
$TranscoderModulesOn = '';
$TranscoderModulesAuto = '';
if (isset($PageOptions['TranscoderFile']) && file_exists($PageOptions['TranscoderFile']) && is_readable($PageOptions['TranscoderFile'])) {
$TranscoderFileContent = file($PageOptions['TranscoderFile']);
for ($i=0; $i < count($TranscoderFileContent); $i++) {
if (substr(trim($TranscoderFileContent[$i]), 0, 1) != '#') {
$TranscoderOption = explode(" ", trim($TranscoderFileContent[$i]));
if (isset($TranscoderOption[0]) && isset($TranscoderOption[1])) {
if ($TranscoderOption[0] === 'ModulesOn') {
$TranscoderModulesOn = trim($TranscoderOption[1]);
} else if ($TranscoderOption[0] === 'ModulesAuto') {
$TranscoderModulesAuto = trim($TranscoderOption[1]);
}
}
}
}
}
$odd = "";
for ($i = 1; $i <= $NumberOfModules; $i++) {
@ -30,11 +49,19 @@ for ($i = 1; $i <= $NumberOfModules; $i++) {
if ($odd == "#FFFFFF") { $odd = "#F1FAFA"; } else { $odd = "#FFFFFF"; }
$transcoderstate = 'Off';
if ((strstr($TranscoderModulesOn,'*') !== false) || (strstr($TranscoderModulesOn,$module) !== false)) {
$transcoderstate = 'On';
} else if ((strstr($TranscoderModulesAuto,'*') !== false) || (strstr($TranscoderModulesAuto,$module) !== false)) {
$transcoderstate = 'Auto';
}
echo '
<tr height="30" bgcolor="'.$odd.'" onMouseOver="this.bgColor=\'#FFFFCA\';" onMouseOut="this.bgColor=\''.$odd.'\';">
<td align="center">'. $module .'</td>
<td align="center">'. (empty($PageOptions['ModuleNames'][$module]) ? '-' : $PageOptions['ModuleNames'][$module]) .'</td>
<td align="center">'. count($Reflector->GetNodesInModulesByID($module)) .'</td>
<td align="center">'. $transcoderstate .'</td>
<td align="center">'. 'REF' . $ReflectorNumber . $module . 'L' .'</td>
<td align="center">'. (is_numeric($ReflectorNumber) ? '*' . sprintf('%01d',$ReflectorNumber) . (($i<=4)?$module:sprintf('%02d',$i)) : '-') .'</td>
<td align="center">'. 'XRF' . $ReflectorNumber . $module . 'L' .'</td>

View file

@ -19,7 +19,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
# change below settings according to your system
NAME="xlxd"
DAEMON="/xlxd/xlxd"
ARGUMENTS="XLX999 192.168.1.240 127.0.0.1"
ARGUMENTS="XLX999 192.168.1.240"
PIDFILE="/var/log/xlxd.pid"
USER=root
GROUP=root

View file

@ -40,7 +40,7 @@ CPacketStream::CPacketStream()
////////////////////////////////////////////////////////////////////////////////////////
// open / close
bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client)
bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client, bool enableTranscoding)
{
bool ok = false;
@ -54,7 +54,11 @@ bool CPacketStream::Open(const CDvHeaderPacket &DvHeader, CClient *client)
m_DvHeader = DvHeader;
m_OwnerClient = client;
m_LastPacketTime.Now();
if (enableTranscoding) {
m_CodecStream = g_Transcoder.GetStream(this, client->GetCodec());
} else {
m_CodecStream = g_Transcoder.GetStream(this, CODEC_NONE);
}
ok = true;
}
return ok;

View file

@ -48,7 +48,7 @@ public:
virtual ~CPacketStream() {};
// open / close
bool Open(const CDvHeaderPacket &, CClient *);
bool Open(const CDvHeaderPacket &, CClient *, bool enableTranscoding);
void Close(void);
// push & pop

View file

@ -214,13 +214,36 @@ CPacketStream *CReflector::OpenStream(CDvHeaderPacket *DvHeader, CClient *client
{
// get the module's queue
char module = DvHeader->GetRpt2Module();
bool enableTranscoding = false;
if (g_Transcoder.IsModuleOn(module))
{
enableTranscoding = true;
}
else if (g_Transcoder.IsModuleAuto(module))
{
// enable transcoding only if we have clients on the module with different codecs
uint8 clientCodecs = 0;
for ( int i = 0; i < m_Clients.GetSize(); i++ )
{
if ( m_Clients.GetClient(i)->GetReflectorModule() == module )
{
clientCodecs |= m_Clients.GetClient(i)->GetCodec();
if ( clientCodecs == (CODEC_AMBEPLUS | CODEC_AMBE2PLUS) ) {
enableTranscoding = true;
break;
}
}
}
}
CPacketStream *stream = GetStream(module);
if ( stream != NULL )
{
// lock it
stream->Lock();
// is it available ?
if ( stream->Open(*DvHeader, client) )
if ( stream->Open(*DvHeader, client, enableTranscoding) )
{
// stream open, mark client as master
// so that it can't be deleted

View file

@ -22,6 +22,8 @@
// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include <string.h>
#include <sys/stat.h>
#include "main.h"
#include "creflector.h"
#include "ctranscoder.h"
@ -55,6 +57,10 @@ CTranscoder::CTranscoder()
m_bStreamOpened = false;
m_StreamidOpenStream = 0;
m_PortOpenStream = 0;
m_ModulesOn = "*"; // default if xlxd.transcoder does not exist
m_ModulesAuto = "";
m_LastNeedReloadTime.Now();
m_LastModTime = 0;
}
////////////////////////////////////////////////////////////////////////////////////////
@ -90,6 +96,8 @@ bool CTranscoder::Init(void)
{
bool ok;
ReadOptions();
// reset stop flag
m_bStopThread = false;
@ -197,6 +205,16 @@ void CTranscoder::Task(void)
// update time
m_LastKeepaliveTime.Now();
}
// check if options need reload every 30 seconds
if ( m_LastNeedReloadTime.DurationSinceNow() > 30 )
{
// reload options if needed
NeedReload();
// update time
m_LastNeedReloadTime.Now();
}
}
////////////////////////////////////////////////////////////////////////////////////////
@ -400,3 +418,105 @@ void CTranscoder::EncodeClosestreamPacket(CBuffer *Buffer, uint16 uiStreamId)
Buffer->Append((uint16)uiStreamId);
}
////////////////////////////////////////////////////////////////////////////////////////
// options helpers
char *CTranscoder::TrimWhiteSpaces(char *str)
{
char *end;
while ((*str == ' ') || (*str == '\t')) str++;
if (*str == 0)
return str;
end = str + strlen(str) - 1;
while ((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end --;
*(end + 1) = 0;
return str;
}
void CTranscoder::NeedReload(void)
{
struct stat fileStat;
if (::stat(TRANSCODEROPTIONS_PATH, &fileStat) != -1)
{
if (m_LastModTime != fileStat.st_mtime)
{
ReadOptions();
}
}
}
void CTranscoder::ReadOptions(void)
{
char sz[256];
int opts = 0;
std::ifstream file(TRANSCODEROPTIONS_PATH);
if (file.is_open())
{
m_ModulesOn = "";
m_ModulesAuto = "";
while (file.getline(sz, sizeof(sz)).good())
{
char *szt = TrimWhiteSpaces(sz);
char *szval;
if ((::strlen(szt) > 0) && szt[0] != '#')
{
if ((szt = ::strtok(szt, " ,\t")) != NULL)
{
if ((szval = ::strtok(NULL, " ,\t")) != NULL)
{
if (::strncmp(szt, "Address", 7) == 0)
{
CIp Ip = CIp(szval);
if (Ip.GetAddr())
{
std::cout << "Transcoder Address set to " << Ip << std::endl;
g_Reflector.SetTranscoderIp(Ip);
m_Ip = Ip;
opts++;
}
}
else if (strncmp(szt, "ModulesOn", 9) == 0)
{
std::cout << "Transcoder ModulesOn set to " << szval << std::endl;
m_ModulesOn = szval;
opts++;
}
else if (strncmp(szt, "ModulesAuto", 11) == 0)
{
std::cout << "Transcoder ModulesAuto set to " << szval << std::endl;
m_ModulesAuto = szval;
opts++;
}
else
{
// unknown option - ignore
}
}
}
}
}
std::cout << "Transcoder loaded " << opts << " options from file " << TRANSCODEROPTIONS_PATH << std::endl;
file.close();
struct stat fileStat;
if (::stat(TRANSCODEROPTIONS_PATH, &fileStat) != -1)
{
m_LastModTime = fileStat.st_mtime;
}
}
}
bool CTranscoder::IsModuleOn(char module)
{
return ( strchr(m_ModulesOn.c_str(), '*') || strchr(m_ModulesOn.c_str(), module) );
}
bool CTranscoder::IsModuleAuto(char module)
{
return ( strchr(m_ModulesAuto.c_str(), '*') || strchr(m_ModulesAuto.c_str(), module) );
}

View file

@ -66,6 +66,10 @@ public:
static void Thread(CTranscoder *);
void Task(void);
// options
bool IsModuleOn(char);
bool IsModuleAuto(char);
protected:
// keepalive helpers
void HandleKeepalives(void);
@ -80,6 +84,11 @@ protected:
void EncodeOpenstreamPacket(CBuffer *, uint8, uint8);
void EncodeClosestreamPacket(CBuffer *, uint16);
// options
char *TrimWhiteSpaces(char *);
void NeedReload(void);
void ReadOptions(void);
protected:
// streams
std::mutex m_Mutex;
@ -103,6 +112,12 @@ protected:
// time
CTimePoint m_LastKeepaliveTime;
CTimePoint m_LastActivityTime;
// options
std::string m_ModulesOn;
std::string m_ModulesAuto;
CTimePoint m_LastNeedReloadTime;
time_t m_LastModTime;
};

View file

@ -87,10 +87,10 @@ int main(int argc, const char * argv[])
#endif
// check arguments
if ( argc != 4 )
if ( argc != 3 )
{
std::cout << "Usage: xlxd callsign xlxdip ambedip" << std::endl;
std::cout << "example: xlxd XLX999 192.168.178.212 127.0.0.1" << std::endl;
std::cout << "Usage: xlxd callsign xlxdip" << std::endl;
std::cout << "example: xlxd XLX999 192.168.178.212" << std::endl;
return 1;
}
@ -100,7 +100,7 @@ int main(int argc, const char * argv[])
// initialize reflector
g_Reflector.SetCallsign(argv[1]);
g_Reflector.SetListenIp(CIp(argv[2]));
g_Reflector.SetTranscoderIp(CIp(CIp(argv[3])));
g_Reflector.SetTranscoderIp(CIp("127.0.0.1")); // default if xlxd.transcoder does not exist
// and let it run
if ( !g_Reflector.Start() )

View file

@ -181,6 +181,7 @@
#define BLACKLIST_PATH "/xlxd/xlxd.blacklist"
#define INTERLINKLIST_PATH "/xlxd/xlxd.interlink"
#define TERMINALOPTIONS_PATH "/xlxd/xlxd.terminal"
#define TRANSCODEROPTIONS_PATH "/xlxd/xlxd.transcoder"
#define DEBUGDUMP_PATH "/var/log/xlxd.debug"
// system constants ---------------------------------------------

View file

@ -31,3 +31,6 @@ install:
[ -f /xlxd/xlxd.terminal ] && \
cp ../config/xlxd.terminal /xlxd/xlxd.terminal.sample || \
cp ../config/xlxd.terminal /xlxd/xlxd.terminal
[ -f /xlxd/xlxd.transcoder ] && \
cp ../config/xlxd.transcoder /xlxd/xlxd.transcoder.sample || \
cp ../config/xlxd.transcoder /xlxd/xlxd.transcoder