mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-11-04 08:04:12 +01:00 
			
		
		
		
	* Refactored ripcd(8) to manage JACK port [dis]connections directly, rather than by delegation to caed(8).
		
			
				
	
	
		
			564 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			564 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// cae_server.cpp
 | 
						|
//
 | 
						|
// Network server for caed(8).
 | 
						|
//
 | 
						|
//   (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
 | 
						|
//
 | 
						|
//   This program is free software; you can redistribute it and/or modify
 | 
						|
//   it under the terms of the GNU General Public License version 2 as
 | 
						|
//   published by the Free Software Foundation.
 | 
						|
//
 | 
						|
//   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, write to the Free Software
 | 
						|
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
//
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#include <qbytearray.h>
 | 
						|
#include <qstringlist.h>
 | 
						|
 | 
						|
#include <rdapplication.h>
 | 
						|
 | 
						|
#include "cae_server.h"
 | 
						|
 | 
						|
//
 | 
						|
// Uncomment this to send all protocol messages to syslog (DEBUG priority)
 | 
						|
//
 | 
						|
// #define __CAE_SERVER_LOG_PROTOCOL_MESSAGES
 | 
						|
 | 
						|
CaeServerConnection::CaeServerConnection(QTcpSocket *sock)
 | 
						|
{
 | 
						|
  socket=sock;
 | 
						|
  authenticated=false;
 | 
						|
  accum="";
 | 
						|
  meter_port=0;
 | 
						|
  for(int i=0;i<RD_MAX_CARDS;i++) {
 | 
						|
    meters_enabled[i]=false;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
CaeServerConnection::~CaeServerConnection()
 | 
						|
{
 | 
						|
  socket->deleteLater();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
CaeServer::CaeServer(RDConfig *config,QObject *parent)
 | 
						|
  : QObject(parent)
 | 
						|
{
 | 
						|
  cae_config=config;
 | 
						|
 | 
						|
  cae_server=new QTcpServer(this);
 | 
						|
  connect(cae_server,SIGNAL(newConnection()),this,SLOT(newConnectionData()));
 | 
						|
 | 
						|
  cae_ready_read_mapper=new QSignalMapper(this);
 | 
						|
  connect(cae_ready_read_mapper,SIGNAL(mapped(int)),
 | 
						|
	  this,SLOT(readyReadData(int)));
 | 
						|
 | 
						|
  cae_connection_closed_mapper=new QSignalMapper(this);
 | 
						|
  connect(cae_connection_closed_mapper,SIGNAL(mapped(int)),
 | 
						|
	  this,SLOT(connectionClosedData(int)));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
QList<int> CaeServer::connectionIds() const
 | 
						|
{
 | 
						|
  QList<int> ret;
 | 
						|
 | 
						|
  for(QMap<int,CaeServerConnection *>::const_iterator it=
 | 
						|
	cae_connections.begin();it!=cae_connections.end();it++) {
 | 
						|
    ret.push_back(it.key());
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
QHostAddress CaeServer::peerAddress(int id) const
 | 
						|
{
 | 
						|
  return cae_connections[id]->socket->peerAddress();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
uint16_t CaeServer::peerPort(int id) const
 | 
						|
{
 | 
						|
  return cae_connections[id]->socket->peerPort();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
uint16_t CaeServer::meterPort(int id) const
 | 
						|
{
 | 
						|
  return cae_connections[id]->meter_port;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::setMeterPort(int id,uint16_t port)
 | 
						|
{
 | 
						|
  cae_connections[id]->meter_port=port;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool CaeServer::metersEnabled(int id,unsigned card) const
 | 
						|
{
 | 
						|
  return cae_connections[id]->meters_enabled[card];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::setMetersEnabled(int id,unsigned card,bool state)
 | 
						|
{
 | 
						|
  cae_connections[id]->meters_enabled[card]=state;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool CaeServer::listen(const QHostAddress &addr,uint16_t port)
 | 
						|
{
 | 
						|
  return cae_server->listen(addr,port);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::sendCommand(const QString &cmd)
 | 
						|
{
 | 
						|
  for(QMap<int,CaeServerConnection *>::const_iterator it=
 | 
						|
	cae_connections.begin();it!=cae_connections.end();it++) {
 | 
						|
    if(it.value()->authenticated) {
 | 
						|
      sendCommand(it.key(),cmd);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::sendCommand(int id,const QString &cmd)
 | 
						|
{
 | 
						|
#ifdef __CAE_SERVER_LOG_PROTOCOL_MESSAGES
 | 
						|
  RDApplication::syslog(cae_config,LOG_DEBUG,
 | 
						|
			"send[%d]: %s",id,(const char *)cmd.toUtf8());
 | 
						|
#endif  // __CAE_SERVER_LOG_PROTOCOL_MESSAGES
 | 
						|
  cae_connections.value(id)->socket->write(cmd.toAscii());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::newConnectionData()
 | 
						|
{
 | 
						|
  QTcpSocket *sock=cae_server->nextPendingConnection();
 | 
						|
 | 
						|
  cae_connection_closed_mapper->setMapping(sock,sock->socketDescriptor());
 | 
						|
  connect(sock,SIGNAL(disconnected()),cae_connection_closed_mapper,SLOT(map()));
 | 
						|
 | 
						|
  cae_ready_read_mapper->setMapping(sock,sock->socketDescriptor());
 | 
						|
  connect(sock,SIGNAL(readyRead()),cae_ready_read_mapper,SLOT(map()));
 | 
						|
 | 
						|
  cae_connections[sock->socketDescriptor()]=new CaeServerConnection(sock);
 | 
						|
 | 
						|
  RDApplication::syslog(cae_config,LOG_DEBUG,
 | 
						|
			"added connection %d",sock->socketDescriptor());
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::readyReadData(int id)
 | 
						|
{
 | 
						|
  QByteArray data=cae_connections.value(id)->socket->readAll();
 | 
						|
  for(int i=0;i<data.size();i++) {
 | 
						|
    char c=0xFF&data[i];
 | 
						|
    switch(c) {
 | 
						|
    case '!':
 | 
						|
      if(ProcessCommand(id,cae_connections.value(id)->accum)) {
 | 
						|
	return;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case 10:
 | 
						|
    case 13:
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      cae_connections.value(id)->accum+=c;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void CaeServer::connectionClosedData(int id)
 | 
						|
{
 | 
						|
  emit connectionDropped(id);
 | 
						|
  cae_connections.value(id)->socket->disconnect();
 | 
						|
  delete cae_connections.value(id);
 | 
						|
  cae_connections.remove(id);
 | 
						|
 | 
						|
  RDApplication::syslog(cae_config,LOG_DEBUG,"removed connection %d",id);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool CaeServer::ProcessCommand(int id,const QString &cmd)
 | 
						|
{
 | 
						|
  CaeServerConnection *conn=cae_connections.value(id);
 | 
						|
  bool ok=false;
 | 
						|
  QStringList f0=cmd.split(" ",QString::SkipEmptyParts);
 | 
						|
 | 
						|
  if(f0.size()==0) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
#ifdef __CAE_SERVER_LOG_PROTOCOL_MESSAGES
 | 
						|
  RDApplication::syslog(cae_config,LOG_DEBUG,
 | 
						|
			"recv[%d]: %s",id,(const char *)cmd.toUtf8());
 | 
						|
#endif  // __CAE_SERVER_LOG_PROTOCOL_MESSAGES
 | 
						|
 | 
						|
  cae_connections.value(id)->accum="";
 | 
						|
 | 
						|
  //
 | 
						|
  // Unpriviledged Commands
 | 
						|
  //
 | 
						|
  if(f0.at(0)=="DC") {
 | 
						|
    connectionClosedData(id);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  if(f0.at(0)=="PW") {
 | 
						|
    if((f0.size()==2)&&(f0.at(1)==cae_config->password())) {
 | 
						|
      conn->authenticated=true;
 | 
						|
      sendCommand(id,"PW +!");
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      conn->authenticated=false;
 | 
						|
      sendCommand(id,"PW -!");
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  }  
 | 
						|
 | 
						|
  //
 | 
						|
  // Priviledged Commands
 | 
						|
  // Authentication required to execute these!
 | 
						|
  //
 | 
						|
  if(!conn->authenticated) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  bool was_processed=false;
 | 
						|
 | 
						|
  if((f0.at(0)=="LP")&&(f0.size()==3)) {  // Load Playback
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      emit loadPlaybackReq(id,card,f0.at(2));
 | 
						|
      was_processed=true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="UP")&&(f0.size()==2)) {  // Unload Playback
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok) {
 | 
						|
      emit unloadPlaybackReq(id,card);
 | 
						|
      was_processed=true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="PP")&&(f0.size()==3)) {  // Play Position
 | 
						|
    unsigned handle=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok) {
 | 
						|
      unsigned pos=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok) {
 | 
						|
	emit playPositionReq(id,handle,pos);
 | 
						|
	was_processed=true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="PY")&&(f0.size()==5)) {  // Play
 | 
						|
    unsigned handle=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok) {
 | 
						|
      unsigned len=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok) {
 | 
						|
	unsigned speed=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok) {
 | 
						|
	  unsigned pitch=f0.at(4).toUInt(&ok);
 | 
						|
	  if(ok) {
 | 
						|
	    emit playReq(id,handle,len,speed,pitch);
 | 
						|
	    was_processed=true;
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="SP")&&(f0.size()==2)) {  // Stop Playback
 | 
						|
    unsigned handle=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok) {
 | 
						|
      emit stopPlaybackReq(id,handle);
 | 
						|
      was_processed=true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="TS")&&(f0.size()==2)) {  // Timescaling Support
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      emit timescalingSupportReq(id,card);
 | 
						|
      was_processed=true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="LR")&&(f0.size()==8)) {  // Load Recording
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	unsigned coding=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok&&(coding<5)) {
 | 
						|
	  unsigned chans=f0.at(4).toUInt(&ok);
 | 
						|
	  if(ok&&(chans<=2)) {
 | 
						|
	    unsigned samprate=f0.at(5).toUInt(&ok);
 | 
						|
	    if(ok) {
 | 
						|
	      unsigned bitrate=f0.at(6).toUInt(&ok);
 | 
						|
	      if(ok) {
 | 
						|
		emit loadRecordingReq(id,card,port,coding,chans,samprate,
 | 
						|
				      bitrate,f0.at(7));
 | 
						|
		was_processed=true;
 | 
						|
	      }
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="UR")&&(f0.size()==3)) {  // Unload Recording
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	emit unloadRecordingReq(id,card,stream);
 | 
						|
	was_processed=true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="RD")&&(f0.size()==5)) {  // Record
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	if(ok) {
 | 
						|
	  unsigned len=f0.at(3).toUInt(&ok);
 | 
						|
	  if(ok) {
 | 
						|
	    int thres=f0.at(4).toInt(&ok);
 | 
						|
	    if(ok) {
 | 
						|
	      emit recordReq(id,card,stream,len,thres);
 | 
						|
	      was_processed=true;
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="SR")&&(f0.size()==3)) {  // Stop Recording
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	if(ok) {
 | 
						|
	  emit stopRecordingReq(id,card,stream);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IV")&&(f0.size()==4)) {  // Set Input Volume
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	if(ok) {
 | 
						|
	  int level=f0.at(3).toInt(&ok);
 | 
						|
	  if(ok) {
 | 
						|
	    emit setInputVolumeReq(id,card,stream,level);
 | 
						|
	    was_processed=true;
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="OV")&&(f0.size()==5)) {  // Set Output Volume
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	if(ok) {
 | 
						|
	  unsigned port=f0.at(3).toUInt(&ok);
 | 
						|
	  if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	    int level=f0.at(4).toInt(&ok);
 | 
						|
	    if(ok) {
 | 
						|
	      emit setOutputVolumeReq(id,card,stream,port,level);
 | 
						|
	      was_processed=true;
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="FV")&&(f0.size()==6)) {  // Fade Output Volume
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	if(ok) {
 | 
						|
	  unsigned port=f0.at(3).toUInt(&ok);
 | 
						|
	  if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	    int level=f0.at(4).toInt(&ok);
 | 
						|
	    if(ok) {
 | 
						|
	      int len=f0.at(5).toUInt(&ok);
 | 
						|
	      if(ok) {
 | 
						|
		emit fadeOutputVolumeReq(id,card,stream,port,level,len);
 | 
						|
		was_processed=true;
 | 
						|
	      }
 | 
						|
	    }
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IL")&&(f0.size()==4)) {  // Set Input Level
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	int level=f0.at(3).toInt(&ok);
 | 
						|
	if(ok) {
 | 
						|
	  emit setInputLevelReq(id,card,port,level);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="OL")&&(f0.size()==4)) {  // Set Output Level
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	int level=f0.at(3).toInt(&ok);
 | 
						|
	if(ok) {
 | 
						|
	  emit setOutputLevelReq(id,card,port,level);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IM")&&(f0.size()==4)) {  // Set Input Mode
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	unsigned mode=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok&&(mode<=3)) {
 | 
						|
	  emit setInputModeReq(id,card,port,mode);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="OM")&&(f0.size()==4)) {  // Set Output Mode
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	unsigned mode=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok&&(mode<=3)) {
 | 
						|
	  emit setOutputModeReq(id,card,port,mode);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IX")&&(f0.size()==4)) {  // Set Input Vox Level
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned stream=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	int level=f0.at(3).toInt(&ok);
 | 
						|
	if(ok) {
 | 
						|
	  emit setInputVoxLevelReq(id,card,stream,level);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IT")&&(f0.size()==4)) {  // Set Input Type
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	int type=f0.at(3).toInt(&ok);
 | 
						|
	if(ok&&(type<=1)) {
 | 
						|
	  emit setInputTypeReq(id,card,port,type);
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="IS")&&(f0.size()==3)) {  // Get Input Status
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	emit getInputStatusReq(id,card,port);
 | 
						|
	was_processed=true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="AL")&&(f0.size()==5)) {  // Set Audio Passthrough Level
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned input=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(input<RD_MAX_PORTS)) {
 | 
						|
	unsigned output=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok&&(output<RD_MAX_PORTS)) {
 | 
						|
	  int level=f0.at(4).toInt(&ok);
 | 
						|
	  if(ok) {
 | 
						|
	    emit setAudioPassthroughLevelReq(id,card,input,output,level);
 | 
						|
	    was_processed=true;
 | 
						|
	  }
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="CS")&&(f0.size()==3)) {  // Set Clock Source
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned input=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(input<RD_MAX_PORTS)) {
 | 
						|
	emit setClockSourceReq(id,card,input);
 | 
						|
	was_processed=true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if((f0.at(0)=="OS")&&(f0.size()==5)) {  // Set Output Status Flag
 | 
						|
    unsigned card=f0.at(1).toUInt(&ok);
 | 
						|
    if(ok&&(card<RD_MAX_CARDS)) {
 | 
						|
      unsigned port=f0.at(2).toUInt(&ok);
 | 
						|
      if(ok&&(port<RD_MAX_PORTS)) {
 | 
						|
	unsigned stream=f0.at(3).toUInt(&ok);
 | 
						|
	if(ok&&(stream<RD_MAX_STREAMS)) {
 | 
						|
	  emit setOutputStatusFlagReq(id,card,port,stream,f0.at(4)=="1");
 | 
						|
	  was_processed=true;
 | 
						|
	}
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if((f0.at(0)=="ME")&&(f0.size()>=3)) {  // Meter Enable
 | 
						|
    uint16_t udp_port=0xFFFF&f0.at(1).toUInt(&ok);
 | 
						|
    if(ok) {
 | 
						|
      QList<unsigned> cards;
 | 
						|
      for(int i=2;i<f0.size();i++) {
 | 
						|
	cards.push_back(f0.at(i).toUInt());
 | 
						|
      }
 | 
						|
      emit meterEnableReq(id,udp_port,cards);
 | 
						|
      was_processed=true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if(!was_processed) {  // Send generic error response
 | 
						|
    sendCommand(id,f0.join(" ")+"-!");
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 |