diff --git a/ChangeLog b/ChangeLog index bbe9d5cf..9a5af86b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24421,3 +24421,6 @@ * Implemented the modified 'Set Audio Passthrough Level' ['AL'] CAE command. * Implemented the new 'Update Audio Ports' ['AP'] CAE command. +2023-09-15 Fred Gleason + * Added a 'Set Timeout' ['TO'] CAE command. + * Added a 'Touch' ['TH'] CAE command. diff --git a/cae/Makefile.am b/cae/Makefile.am index 595c1d79..b92989bd 100644 --- a/cae/Makefile.am +++ b/cae/Makefile.am @@ -1,4 +1,4 @@ -## automake.am +## Makefile.am ## ## Core Audio Engine Makefile.am for Rivendell ## @@ -31,6 +31,7 @@ sbin_PROGRAMS = caed dist_caed_SOURCES = cae.cpp cae.h\ cae_server.cpp cae_server.h\ + connection.cpp connection.h\ driver.cpp driver.h\ driver_alsa.cpp driver_alsa.h\ driver_hpi.cpp driver_hpi.h\ @@ -39,6 +40,7 @@ dist_caed_SOURCES = cae.cpp cae.h\ nodist_caed_SOURCES = moc_cae.cpp\ moc_cae_server.cpp\ + moc_connection.cpp\ moc_driver.cpp\ moc_driver_alsa.cpp\ moc_driver_hpi.cpp\ diff --git a/cae/cae.cpp b/cae/cae.cpp index 05ccf201..9b530a1d 100644 --- a/cae/cae.cpp +++ b/cae/cae.cpp @@ -145,12 +145,14 @@ MainObject::MainObject(QObject *parent) // Server Front End // cae_server=new CaeServer(this); - if(!cae_server->listen(QHostAddress::Any,CAED_TCP_PORT)) { + if(!cae_server->bind(QHostAddress::Any,CAED_TCP_PORT)) { rda->syslog(LOG_ERR,"caed: failed to bind port %d",CAED_TCP_PORT); exit(1); } - connect(cae_server,SIGNAL(connectionDropped(int)), - this,SLOT(connectionDroppedData(int))); + // connect(cae_server,SIGNAL(connectionDropped(int)), + // this,SLOT(connectionDroppedData(int))); + connect(cae_server,SIGNAL(connectionClosed(const SessionId &)), + this,SLOT(connectionClosedData(const SessionId &))); connect(cae_server,SIGNAL(playPositionReq(const SessionId &,int)), this,SLOT(playPositionData(const SessionId &,int))); connect(cae_server,SIGNAL(startPlaybackReq(const SessionId &,const QString &, @@ -159,7 +161,6 @@ MainObject::MainObject(QObject *parent) unsigned,unsigned,int,int,int))); connect(cae_server,SIGNAL(playStopReq(const SessionId &)), this,SLOT(stopPlaybackData(const SessionId &))); - /* connect(cae_server,SIGNAL(loadPlaybackReq(int,unsigned,const QString &)), this,SLOT(loadPlaybackData(int,unsigned,const QString &))); connect(cae_server,SIGNAL(unloadPlaybackReq(int,unsigned)), @@ -198,6 +199,7 @@ MainObject::MainObject(QObject *parent) unsigned,int,unsigned)), this,SLOT(fadeOutputVolumeData(int,unsigned,unsigned, unsigned,int,unsigned))); + /* connect(cae_server,SIGNAL(setInputLevelReq(int,unsigned,unsigned,int)), this,SLOT(setInputLevelData(int,unsigned,unsigned,int))); connect(cae_server,SIGNAL(setOutputLevelReq(int,unsigned,unsigned,int)), @@ -236,11 +238,11 @@ MainObject::MainObject(QObject *parent) this, SLOT(openRtpCaptureChannelData(int,unsigned,unsigned,uint16_t, unsigned,unsigned))); + */ connect(cae_server,SIGNAL(meterEnableReq(const QHostAddress &,uint16_t, const QList &)), this,SLOT(meterEnableData(const QHostAddress &,uint16_t, const QList &))); - */ signal(SIGHUP,SigHandler); signal(SIGINT,SigHandler); signal(SIGTERM,SigHandler); @@ -412,7 +414,7 @@ void MainObject::startPlaybackData(const SessionId &sid,const QString &cutname, sess->setStartPosition(start_pos); sess->setEndPosition(end_pos); sess->setSpeed(speed); - cae_sessions[sid]=sess; + cae_play_sessions[sid]=sess; rda->syslog(LOG_DEBUG,"playback started - session: %s card: %d port: %d stream: %d filename: %s", sid.dump().toUtf8().constData(),cardnum,portnum,streamnum, @@ -428,7 +430,7 @@ void MainObject::playPositionData(const SessionId &sid,int position) // // Find the session // - if((sess=cae_sessions.value(sid))==NULL) { + if((sess=cae_play_sessions.value(sid))==NULL) { rda->syslog(LOG_WARNING, "attempting to position non-existent session - session: %s", sid.dump().toUtf8().constData()); @@ -449,8 +451,7 @@ void MainObject::playPositionData(const SessionId &sid,int position) sid.dump().toUtf8().constData(),position); return; } - cae_server->sendCommand(sid,QString::asprintf("PP %d %d %d", - sid.processId(), + cae_server->sendCommand(sid,QString::asprintf("PP %d %d", sid.serialNumber(), position)); rda->syslog(LOG_DEBUG,"play position succeeded - session: %s position: %d", @@ -460,45 +461,23 @@ void MainObject::playPositionData(const SessionId &sid,int position) void MainObject::stopPlaybackData(const SessionId &sid) { + // + // Maintainer's Note: + // *Do not* call this from an iterator! Use StopPlayout() instead. + // Session *sess=NULL; - Driver *dvr=NULL; // // Find the session // - if((sess=cae_sessions.value(sid))==NULL) { + if((sess=cae_play_sessions.value(sid))==NULL) { rda->syslog(LOG_WARNING, "attempting to stop playing non-existent session - session: %s", sid.dump().toUtf8().constData()); return; } - // - // Find the card - // - if((dvr=GetDriver(sess->cardNumber()))==NULL) { - rda->syslog(LOG_WARNING,"no such card - session: %s card: %d", - sid.dump().toUtf8().constData(),sess->cardNumber()); - return; - } - - // - // Stop Transport - // - if(!dvr->stopPlayback(sess->cardNumber(),sess->streamNumber())) { - rda->syslog(LOG_WARNING, - "stop playback failed - session: %s", - sid.dump().toUtf8().constData()); - } - - // - // Unload - // - if(!dvr->unloadPlayback(sess->cardNumber(),sess->streamNumber())) { - rda->syslog(LOG_WARNING, - "unload playback failed - session: %s", - sid.dump().toUtf8().constData()); - } + StopPlayout(sess); // // Delete session @@ -506,7 +485,7 @@ void MainObject::stopPlaybackData(const SessionId &sid) QString msg=QString::asprintf("stopped playback - session: %s", sid.dump().toUtf8().constData()); delete sess; - cae_sessions.remove(sid); + cae_play_sessions.remove(sid); rda->syslog(LOG_DEBUG,"%s",msg.toUtf8().constData()); } @@ -1263,19 +1242,14 @@ void MainObject::openRtpCaptureChannelData(int id,unsigned card,unsigned port, { } - +/* void MainObject::meterEnableData(const QHostAddress &addr,uint16_t udp_port, const QList &cards) { - /* QString cmd=QString::asprintf("ME %u",0xFFFF&udp_port); for(int i=0;i0xFFFF)) { - cae_server->sendCommand(id,cmd+" -!"); - return; - } cae_server->setMeterPort(id,udp_port); for(int i=0;i=RD_MAX_CARDS)) { @@ -1285,31 +1259,55 @@ void MainObject::meterEnableData(const QHostAddress &addr,uint16_t udp_port, cae_server->setMetersEnabled(id,cards.at(i),true); } - cae_server->sendCommand(id,cmd+" +!"); + // cae_server->sendCommand(id,cmd+" +!"); SendMeterOutputStatusUpdate(); - */ } - - +*/ +/* void MainObject::connectionDroppedData(int id) { KillSocket(id); } +*/ + + +void MainObject::connectionClosedData(const SessionId &sid) +{ + rda->syslog(LOG_DEBUG,"cleaning up sessions from %s", + sid.dump().toUtf8().constData()); + + // + // Clean up active play sessions + // + QMutableMapIterator it(cae_play_sessions); + while(it.hasNext()) { + it.next(); + if(it.key().belongsTo(sid)) { + StopPlayout(it.value()); + delete it.value(); + it.remove(); + } + } + + // + // Clean up active record sessions + // + // FIXME: Implement this! +} void MainObject::statePlayUpdate(int card,int stream,int state) { if(state==0) { // Stopped - for(QMap::iterator it=cae_sessions.begin(); - it!=cae_sessions.end();it++) { + for(QMap::iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { if((it.value()->cardNumber()==card)&& (it.value()->streamNumber()==stream)) { cae_server-> - sendCommand(it.key(),QString::asprintf("SP %d %d", - it.key().processId(), + sendCommand(it.key(),QString::asprintf("SP %d", it.key().serialNumber())); delete it.value(); - cae_sessions.remove(it.key()); + cae_play_sessions.remove(it.key()); return; } } @@ -1431,6 +1429,40 @@ void MainObject::updateMeters() } +void MainObject::StopPlayout(Session *sess) +{ + Driver *dvr=NULL; + + // + // Find the card + // + if((dvr=GetDriver(sess->cardNumber()))==NULL) { + rda->syslog(LOG_WARNING,"no such card - session: %s card: %d", + sess->sessionId().dump().toUtf8().constData(), + sess->cardNumber()); + return; + } + + // + // Stop Transport + // + if(!dvr->stopPlayback(sess->cardNumber(),sess->streamNumber())) { + rda->syslog(LOG_WARNING, + "stop playback failed - session: %s", + sess->sessionId().dump().toUtf8().constData()); + } + + // + // Unload + // + if(!dvr->unloadPlayback(sess->cardNumber(),sess->streamNumber())) { + rda->syslog(LOG_WARNING, + "unload playback failed - session: %s", + sess->sessionId().dump().toUtf8().constData()); + } +} + + void MainObject::InitProvisioning() const { QString sql; @@ -1513,7 +1545,7 @@ void MainObject::InitMixers() } } - +/* void MainObject::KillSocket(int ch) { for(int i=0;i ids=cae_server->connectionIds(); - - for(int l=0;lmeterPort(ids.at(l))>0)&& - cae_server->metersEnabled(ids.at(l),cardnum)) { + for(QMap::const_iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { + if((it.value()->cardNumber()==cardnum)&&(it.value()->meterPort()>0)&& + (it.value()->metersEnabled())) { SendMeterUpdate(QString::asprintf("ML %s %d %d %d %d", type.toUtf8().constData(), cardnum,portnum,levels[0],levels[1]), - ids.at(l)); + it.value()); + } } } @@ -1849,13 +1881,13 @@ void MainObject::SendMeterLevelUpdate(const QString &type,int cardnum, void MainObject::SendStreamMeterLevelUpdate(int cardnum,int streamnum, short levels[]) { - QList ids=cae_server->connectionIds(); - - for(int l=0;lmeterPort(ids.at(l))>0)&& - cae_server->metersEnabled(ids.at(l),cardnum)) { + for(QMap::const_iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { + if((it.value()->cardNumber()==cardnum)&&(it.value()->meterPort()>0)&& + (it.value()->metersEnabled())) { SendMeterUpdate(QString::asprintf("MO %d %d %d %d", - cardnum,streamnum,levels[0],levels[1]),ids.at(l)); + cardnum,streamnum,levels[0],levels[1]), + it.value()); } } } @@ -1863,14 +1895,13 @@ void MainObject::SendStreamMeterLevelUpdate(int cardnum,int streamnum, void MainObject::SendMeterPositionUpdate(int cardnum,unsigned pos[]) { - QList ids=cae_server->connectionIds(); - for(unsigned k=0;kmeterPort(ids.at(l))>0)&& - cae_server->metersEnabled(ids.at(l),cardnum)) { + for(QMap::const_iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { + if((it.value()->cardNumber()==cardnum)&&(it.value()->meterPort()>0)&& + (it.value()->metersEnabled())) { SendMeterUpdate(QString::asprintf("MP %d %d %d",cardnum,k,pos[k]), - ids.at(l)); + it.value()); } } } @@ -1879,17 +1910,17 @@ void MainObject::SendMeterPositionUpdate(int cardnum,unsigned pos[]) void MainObject::SendMeterOutputStatusUpdate() { - QList ids=cae_server->connectionIds(); - - for(unsigned i=0;imeterPort(ids.at(l))>0)&& - cae_server->metersEnabled(ids.at(l),i)) { + for(QMap::const_iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { + if((it.value()->cardNumber()==i)&& + (it.value()->meterPort()>0)&&(it.value()->metersEnabled())) { SendMeterUpdate(QString::asprintf("MS %d %d %d %d",i,j,k, - output_status_flag[i][j][k]),ids.at(l)); + output_status_flag[i][j][k]), + it.value()); } } } @@ -1901,21 +1932,22 @@ void MainObject::SendMeterOutputStatusUpdate() void MainObject::SendMeterOutputStatusUpdate(int card,int port,int stream) { - QList ids=cae_server->connectionIds(); - - for(int l=0;lmeterPort(ids.at(l))>0)&& - cae_server->metersEnabled(ids.at(l),card)) { + for(QMap::const_iterator it=cae_play_sessions.begin(); + it!=cae_play_sessions.end();it++) { + if((it.value()->streamNumber()==stream)&&(it.value()->meterPort()>0)&& + (it.value()->metersEnabled())) { SendMeterUpdate(QString::asprintf("MS %d %d %d %d",card,port,stream, - output_status_flag[card][port][stream]),ids.at(l)); + output_status_flag[card][port][stream]), + it.value()); } } } -void MainObject::SendMeterUpdate(const QString &msg,int conn_id) + +void MainObject::SendMeterUpdate(const QString &msg,Session *sess) { - meter_socket->writeDatagram(msg.toUtf8(),cae_server->peerAddress(conn_id), - cae_server->meterPort(conn_id)); + meter_socket->writeDatagram(msg.toUtf8(),sess->sessionId().address(), + sess->meterPort()); } diff --git a/cae/cae.h b/cae/cae.h index 7ed27bab..90347bc1 100644 --- a/cae/cae.h +++ b/cae/cae.h @@ -47,8 +47,8 @@ #include #include -#include "driver.h" #include "cae_server.h" +#include "driver.h" #ifndef HAVE_SRC_CONV void src_int_to_float_array (const int *in, float *out, int len); @@ -123,17 +123,20 @@ class MainObject : public QObject void openRtpCaptureChannelData(int id,unsigned card,unsigned port, uint16_t udp_port,unsigned samprate, unsigned chans); - void meterEnableData(const QHostAddress &addr,uint16_t udp_port, - const QList &cards); + // void meterEnableData(const QHostAddress &addr,uint16_t udp_port, + // const QList &cards); void statePlayUpdate(int card,int stream,int state); void stateRecordUpdate(int card,int stream,int state); void updateMeters(); - void connectionDroppedData(int id); + // void connectionDroppedData(int id); + void connectionClosedData(const SessionId &sid); private: + void StopPlayout(Session *sess); + void InitProvisioning() const; void InitMixers(); - void KillSocket(int); + // void KillSocket(int); bool CheckDaemon(QString); pid_t GetPid(QString pidfile); int GetNextHandle(); @@ -146,7 +149,8 @@ class MainObject : public QObject void SendMeterPositionUpdate(int cardnum,unsigned pos[]); void SendMeterOutputStatusUpdate(); void SendMeterOutputStatusUpdate(int card,int port,int stream); - void SendMeterUpdate(const QString &msg,int conn_id); + // void SendMeterUpdate(const QString &msg,int conn_id); + void SendMeterUpdate(const QString &msg,Session *sess); Driver *GetDriver(unsigned card) const; void MakeDriver(unsigned *next_card,RDStation::AudioDriver type); QList d_drivers; @@ -171,7 +175,7 @@ class MainObject : public QObject } play_handle[256]; int next_play_handle; - QMap cae_sessions; + QMap cae_play_sessions; private: bool CheckLame(); diff --git a/cae/cae_server.cpp b/cae/cae_server.cpp index e6080af0..3b02d39f 100644 --- a/cae/cae_server.cpp +++ b/cae/cae_server.cpp @@ -42,60 +42,7 @@ CaeServer::CaeServer(QObject *parent) } -QList CaeServer::connectionIds() const -{ - QList ret; - /* - for(QMap::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(); - return QHostAddress(); -} - - -uint16_t CaeServer::peerPort(int id) const -{ - // return cae_connections[id]->socket->peerPort(); - return 0; -} - - -uint16_t CaeServer::meterPort(int id) const -{ - // return cae_connections[id]->meter_port; - return 0; -} - - -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]; - return false; -} - - -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) +bool CaeServer::bind(const QHostAddress &addr,uint16_t port) { return d_server_socket->bind(port); } @@ -124,26 +71,6 @@ void CaeServer::sendCommand(const SessionId &dest,const QString &cmd) } -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 [%s:%u]",sock->socketDescriptor(), - sock->peerAddress().toString().toUtf8().constData(), - 0xFFFF&sock->peerPort()); - */ -} - - void CaeServer::readyReadData() { QNetworkDatagram dgram=d_server_socket->receiveDatagram(1500); @@ -152,9 +79,20 @@ void CaeServer::readyReadData() } +void CaeServer::connectionExpiredData(const SessionId &sid) +{ + Connection *conn=cae_connections.value(sid); + + if(conn!=NULL) { + conn->deleteLater(); + cae_connections.remove(sid); + emit connectionClosed(sid); + } +} + +/* void CaeServer::connectionClosedData(int id) { - /* QString logmsg= QString::asprintf("removed connection %d [%s:%u]", id, @@ -175,9 +113,8 @@ void CaeServer::connectionClosedData(int id) cae_connections.remove(id); RDApplication::syslog(cae_config,priority,"%s",logmsg.toUtf8().constData()); - */ } - +*/ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, const QString &cmd) @@ -185,7 +122,6 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, bool was_processed=false; bool ok=false; QStringList f0=cmd.split(" ",QString::SkipEmptyParts); - pid_t pid; unsigned serial; QString cutname; unsigned cardnum; @@ -200,34 +136,61 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, int coding; int channels; int bitrate; + int interval; SessionId origin(src_addr,src_port); + // + // Connection Management + // + if((f0.at(0)=="TO")&&(f0.size()==2)) { // Set Timeout + interval=f0.at(1).toInt(&ok); + if(ok&&(interval>=0)) { + Connection *conn=cae_connections.value(origin); + if(conn==NULL) { + conn=new Connection(origin,this); + connect(conn,SIGNAL(connectionExpired(const SessionId &)), + this,SLOT(connectionExpiredData(const SessionId &))); + cae_connections[origin]=conn; + } + conn->setTimeout(interval); + was_processed=true; + } + } + + if((f0.at(0)=="TH")&&(f0.size()==1)) { // Touch + Connection *conn=cae_connections.value(origin); + if(conn==NULL) { + rda->syslog(LOG_WARNING,"%s attempted to touch non-existent connection", + origin.dump().toUtf8().constData()); + } + else { + conn->touch(); + } + was_processed=true; + } + // // Playback Operations // - if((f0.at(0)=="PY")&&(f0.size()==9)) { // Start Playback - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - cutname=f0.at(3); - if(cutname.length()==10) { - cardnum=f0.at(4).toUInt(&ok); - if(ok&&(cardnum=0)) { - end_pos=f0.at(7).toInt(&ok); - if(ok&&(end_pos>=0)&&(end_pos>=start_pos)) { - speed=f0.at(8).toInt(&ok); - if(ok&&(speed>0)) { - emit startPlaybackReq(origin,cutname,cardnum,portnum, - start_pos,end_pos,speed); - was_processed=true; - } + if((f0.at(0)=="PY")&&(f0.size()==8)) { // Start Playback + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + cutname=f0.at(2); + if(cutname.length()==10) { + cardnum=f0.at(3).toUInt(&ok); + if(ok&&(cardnum=0)) { + end_pos=f0.at(6).toInt(&ok); + if(ok&&(end_pos>=0)&&(end_pos>=start_pos)) { + speed=f0.at(7).toInt(&ok); + if(ok&&(speed>0)) { + emit startPlaybackReq(origin,cutname,cardnum,portnum, + start_pos,end_pos,speed); + was_processed=true; } } } @@ -237,122 +200,94 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, } } - if((f0.at(0)=="PP")&&(f0.size()==4)) { // Play Position - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); + if((f0.at(0)=="PP")&&(f0.size()==3)) { // Play Position + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + position=f0.at(2).toInt(&ok); + if(ok&&(position>=0)) { + emit playPositionReq(origin,position); + was_processed=true; + } + } + } + + if((f0.at(0)=="PE")&&(f0.size()==2)) { // Pause Playback + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + emit playPauseReq(origin); + was_processed=true; + } + } + + if((f0.at(0)=="PR")&&(f0.size()==2)) { // Resume Playback + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + emit playResumeReq(origin); + was_processed=true; + } + } + + if((f0.at(0)=="SP")&&(f0.size()==2)) { // Stop Playback + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + emit playStopReq(origin); + was_processed=true; + } + } + + if((f0.at(0)=="OV")&&(f0.size()==3)) { // Set Output Volume + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + level=f0.at(2).toInt(&ok); if(ok) { - origin.setSerialNumber(serial); - position=f0.at(3).toInt(&ok); - if(ok&&(position>=0)) { - emit playPositionReq(origin,position); + emit playSetOutputVolumeReq(origin,level); + was_processed=true; + } + } + } + + if((f0.at(0)=="FV")&&(f0.size()==4)) { // Fade Output Volume + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + level=f0.at(2).toInt(&ok); + if(ok) { + length=f0.at(3).toInt(&ok); + if(ok&&length>=0) { + emit playFadeOutputVolumeReq(origin,level,length); was_processed=true; } } } } - if((f0.at(0)=="PE")&&(f0.size()==3)) { // Pause Playback - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - emit playPauseReq(origin); - was_processed=true; - } - } - } - - if((f0.at(0)=="PR")&&(f0.size()==3)) { // Resume Playback - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - emit playResumeReq(origin); - was_processed=true; - } - } - } - - if((f0.at(0)=="SP")&&(f0.size()==3)) { // Stop Playback - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - emit playStopReq(origin); - was_processed=true; - } - } - } - - if((f0.at(0)=="OV")&&(f0.size()==4)) { // Set Output Volume - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - level=f0.at(3).toInt(&ok); - if(ok) { - emit playSetOutputVolumeReq(origin,level); - was_processed=true; - } - } - } - } - - if((f0.at(0)=="FV")&&(f0.size()==5)) { // Fade Output Volume - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - level=f0.at(3).toInt(&ok); - if(ok) { - length=f0.at(4).toInt(&ok); - if(ok&&length>=0) { - emit playFadeOutputVolumeReq(origin,level,length); - was_processed=true; - } - } - } - } - } - // // Record Operations // - if((f0.at(0)=="LR")&&(f0.size()==10)) { // Cue Recording - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - cutname=f0.at(3); - if(cutname.length()==10) { - cardnum=f0.at(4).toUInt(&ok); - if(ok&&(cardnum=0)&&(coding<=4)) { - channels=f0.at(7).toInt(&ok); - if(ok&&(channels>0)) { - bitrate=f0.at(8).toInt(&ok); - if(ok&&(bitrate>=0)) { - emit recordCueReq(origin,cutname,cardnum,portnum, - coding,channels,bitrate); - was_processed=true; - } + if((f0.at(0)=="LR")&&(f0.size()==8)) { // Cue Recording + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + cutname=f0.at(2); + if(cutname.length()==10) { + cardnum=f0.at(3).toUInt(&ok); + if(ok&&(cardnum=0)&&(coding<=4)) { + channels=f0.at(6).toInt(&ok); + if(ok&&(channels>0)) { + bitrate=f0.at(7).toInt(&ok); + if(ok&&(bitrate>=0)) { + emit recordCueReq(origin,cutname,cardnum,portnum, + coding,channels,bitrate); + was_processed=true; } } } @@ -362,54 +297,46 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, } } - if((f0.at(0)=="RD")&&(f0.size()==5)) { // Start Recording - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - length=f0.at(3).toInt(&ok); - if(ok&&(length>=0)) { - threshold=f0.at(4).toInt(&ok); - if(ok&&(threshold<=0)) { - emit recordStartReq(origin,length,threshold); - was_processed=true; - } + if((f0.at(0)=="RD")&&(f0.size()==4)) { // Start Recording + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + length=f0.at(2).toInt(&ok); + if(ok&&(length>=0)) { + threshold=f0.at(3).toInt(&ok); + if(ok&&(threshold<=0)) { + emit recordStartReq(origin,length,threshold); + was_processed=true; } } } } - if((f0.at(0)=="RC")&&(f0.size()==11)) { // Cue and Start Recording - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - cutname=f0.at(3); - if(cutname.length()==10) { - cardnum=f0.at(4).toUInt(&ok); - if(ok&&(cardnum=0)&&(coding<=4)) { - channels=f0.at(7).toInt(&ok); - if(ok&&(channels>0)) { - bitrate=f0.at(8).toInt(&ok); - if(ok&&(bitrate>=0)) { - length=f0.at(9).toInt(&ok); - if(ok&&(length>=0)) { - threshold=f0.at(10).toInt(&ok); - if(ok&&(threshold<=0)) { - emit recordCueAndStartReq(origin,cutname, - cardnum,portnum, - coding,channels,bitrate, - length,threshold); - was_processed=true; - } + if((f0.at(0)=="RC")&&(f0.size()==10)) { // Cue and Start Recording + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + cutname=f0.at(2); + if(cutname.length()==10) { + cardnum=f0.at(3).toUInt(&ok); + if(ok&&(cardnum=0)&&(coding<=4)) { + channels=f0.at(6).toInt(&ok); + if(ok&&(channels>0)) { + bitrate=f0.at(7).toInt(&ok); + if(ok&&(bitrate>=0)) { + length=f0.at(8).toInt(&ok); + if(ok&&(length>=0)) { + threshold=f0.at(9).toInt(&ok); + if(ok&&(threshold<=0)) { + emit recordCueAndStartReq(origin,cutname, + cardnum,portnum, + coding,channels,bitrate, + length,threshold); + was_processed=true; } } } @@ -421,16 +348,12 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, } } - if((f0.at(0)=="SR")&&(f0.size()==3)) { // Stop Recording - pid=f0.at(1).toUInt(&ok); - if(ok&&(pid>0)) { - origin.setProcessId(pid); - serial=f0.at(2).toUInt(&ok); - if(ok) { - origin.setSerialNumber(serial); - emit recordStopReq(origin); - was_processed=true; - } + if((f0.at(0)=="SR")&&(f0.size()==2)) { // Stop Recording + serial=f0.at(1).toUInt(&ok); + if(ok) { + origin.setSerialNumber(serial); + emit recordStopReq(origin); + was_processed=true; } } @@ -483,10 +406,6 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, // // Meter Commands // - /* - * This needs to die! - * Replace with multicast meter system. - * if(f0.at(0)=="ME") { // Meter Enable if(f0.size()>2) { // So we don't warn if no cards are specified uint16_t udp_port=0xFFFF&f0.at(1).toUInt(&ok); @@ -500,7 +419,6 @@ bool CaeServer::ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, } was_processed=true; } - */ if(!was_processed) { rda->syslog(LOG_WARNING, diff --git a/cae/cae_server.h b/cae/cae_server.h index b320bf25..f2346a26 100644 --- a/cae/cae_server.h +++ b/cae/cae_server.h @@ -31,6 +31,7 @@ #include +#include "connection.h" #include "session.h" class CaeServer : public QObject @@ -38,23 +39,19 @@ class CaeServer : public QObject Q_OBJECT; public: CaeServer(QObject *parent=0); - QList connectionIds() const; - QHostAddress peerAddress(int id) const; - uint16_t peerPort(int id) const; - uint16_t meterPort(int id) const; - void setMeterPort(int id,uint16_t port); bool metersEnabled(int id,unsigned card) const; void setMetersEnabled(int id,unsigned card,bool state); - bool listen(const QHostAddress &addr,uint16_t port); + bool bind(const QHostAddress &addr,uint16_t port); void sendCommand(const QString &cmd); void sendCommand(const SessionId &dest,const QString &cmd); signals: - void connectionDropped(int id); + // void connectionDropped(int id); // // New Signals // + void connectionClosed(const SessionId &sid); void startPlaybackReq(const SessionId &sid,const QString &cutname, unsigned cardnum,unsigned portnum, int start_pos,int end_pos,int speed); @@ -111,13 +108,14 @@ class CaeServer : public QObject const QList &cards); private slots: - void newConnectionData(); void readyReadData(); - void connectionClosedData(int id); + void connectionExpiredData(const SessionId &sid); + // void connectionClosedData(int id); private: bool ProcessCommand(const QHostAddress &src_addr,uint16_t src_port, const QString &cmd); + QMap cae_connections; QSignalMapper *cae_ready_read_mapper; QUdpSocket *d_server_socket; }; diff --git a/cae/connection.cpp b/cae/connection.cpp new file mode 100644 index 00000000..72dc5f35 --- /dev/null +++ b/cae/connection.cpp @@ -0,0 +1,83 @@ +// connection.cpp +// +// UDP connection context for CAE protocol commands +// +// (C) Copyright 2023 Fred Gleason +// +// 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 "connection.h" + +Connection::Connection(const SessionId &sid,QObject *parent) + : QObject(parent) +{ + d_session_id=sid; + d_interval=0; + + d_timer=new QTimer(this); + d_timer->setSingleShot(true); + connect(d_timer,SIGNAL(timeout()),this,SLOT(timerData())); +} + + +Connection::~Connection() +{ + delete d_timer; +} + + +SessionId Connection::sessionId() const +{ + return d_session_id; +} + + +QString Connection::dump() const +{ + return d_session_id.dump(); +} + + +bool Connection::operator!=(const Connection &other) const +{ + return (other.d_session_id.address()!=d_session_id.address())|| + (other.d_session_id.port()!=d_session_id.port()); +} + + +bool Connection::operator<(const Connection &other) const +{ + return other.d_session_idstop(); + d_timer->start(d_interval); +} + + +void Connection::timerData() +{ + emit connectionExpired(d_session_id); +} diff --git a/cae/connection.h b/cae/connection.h new file mode 100644 index 00000000..ef2269ba --- /dev/null +++ b/cae/connection.h @@ -0,0 +1,60 @@ +// connection.h +// +// UDP connection context for CAE protocol commands +// +// (C) Copyright 2023 Fred Gleason +// +// 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. +// + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include + +#include +#include +#include + +#include "session.h" + +class Connection : public QObject +{ + Q_OBJECT; + public: + Connection(const SessionId &sid,QObject *parent); + ~Connection(); + SessionId sessionId() const; + QString dump() const; + bool operator!=(const Connection &other) const; + bool operator<(const Connection &other) const; + + signals: + void connectionExpired(const SessionId &sid); + + public slots: + void setTimeout(int msecs); + void touch(); + + private slots: + void timerData(); + + private: + SessionId d_session_id; + QTimer *d_timer; + int d_interval; +}; + + +#endif // SESSION_H diff --git a/cae/session.cpp b/cae/session.cpp index 48219280..375f914c 100644 --- a/cae/session.cpp +++ b/cae/session.cpp @@ -20,19 +20,16 @@ #include "session.h" -SessionId::SessionId(const QHostAddress &addr,uint16_t port,int pid,int serial) +SessionId::SessionId(const QHostAddress &src_addr,uint16_t src_port,int serial) { - d_address=addr; - d_port=port; - d_process_id=pid; + d_address=src_addr; + d_port=src_port; d_serial_number=serial; } SessionId::SessionId() { - d_port=0; - d_process_id=0; d_serial_number=0; } @@ -49,18 +46,6 @@ uint16_t SessionId::port() const } -int SessionId::processId() const -{ - return d_process_id; -} - - -void SessionId::setProcessId(int pid) -{ - d_process_id=pid; -} - - int SessionId::serialNumber() const { return d_serial_number; @@ -75,31 +60,41 @@ void SessionId::setSerialNumber(int serial) QString SessionId::dump() const { - return address().toString()+ - QString::asprintf(":%d:%d:%d",0xFFFF&port(),processId(),serialNumber()); + return QString::asprintf("%s:%d:%d",d_address.toString().toUtf8().constData(), + 0xFFFF&d_port,d_serial_number); +} + + +bool SessionId::belongsTo(const SessionId &other) const +{ + return ((other.d_address==d_address)&&(other.d_port==d_port)); +} + + +bool SessionId::operator!=(const SessionId &other) const +{ + return (other.d_address!=d_address)||(other.d_port!=d_port)|| + (other.d_serial_number!=d_serial_number); } bool SessionId::operator<(const SessionId &other) const { - if(other.d_address!=d_address) { + if(other.d_address.toIPv4Address()!=d_address.toIPv4Address()) { return other.d_address.toIPv4Address() + + Connection Management + + + Commands + + Set Timeout + + Set the timeout interval for the connection. + + + + TO + interval + + + + + interval + + + When set to a non-zero value, the client must send a + + Touch message + + at an interval of least that many milliseconds, otherwise + the engine will clear the connection, releasing all associated + resources. + + + + + + + Touch + + Keep connection alive. + + + + TH + + + + + + + Playback Operations @@ -156,7 +204,6 @@ PY - pid serial cut-name card-num @@ -167,15 +214,6 @@ - - pid - - - An integer value, giving the process ID of the process - originating the command. - - - serial @@ -183,7 +221,7 @@ An integer value, giving the serial number of the command. This can be any 32 bit positive integer value, but must be unique within the scope of the - process originating the command! + connection sending the command! @@ -249,24 +287,11 @@ PP - pid serial position - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -302,23 +327,10 @@ PE - pid serial - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -343,23 +355,10 @@ PR - pid serial - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -384,23 +383,10 @@ SP - pid serial - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -424,24 +410,11 @@ OV - pid serial level - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -475,25 +448,12 @@ FV - pid serial level length - - pid - - - Integer value. Should be the same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -540,23 +500,10 @@ SP - pid serial - - pid - - - Integer value. The same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -580,24 +527,11 @@ PP - pid serial position - - pid - - - Integer value. The same value as that used in the prior - - Start Playback - - operation. - - - serial @@ -640,7 +574,6 @@ LR - pid serial cut-name card-num @@ -651,15 +584,6 @@ - - pid - - - An integer value, giving the process ID of the process - originating the command. - - - serial @@ -667,7 +591,7 @@ An integer value, giving the serial number of the command. This can be any 32 bit positive integer value, but must be unique within the scope of the - process originating the command! + connection sending the command! @@ -749,25 +673,12 @@ RD - pid serial length threshold - - pid - - - Integer value. The same value as that used in the prior - - Cue Recording - - operation. - - - serial @@ -813,7 +724,6 @@ RC - pid serial cut-name card-num @@ -826,15 +736,6 @@ - - pid - - - An integer value, giving the process ID of the process - originating the command. - - - serial @@ -842,7 +743,7 @@ An integer value, giving the serial number of the command. This can be any 32 bit positive integer value, but must be unique within the scope of the - process originating the command! + connection sending the command! @@ -941,27 +842,10 @@ SR - pid serial - - pid - - - Integer value. The same value as that used in the prior - - Cue Recording - - or - - Cue and Start Recording - - operation. - - - serial @@ -994,28 +878,11 @@ RS - pid serial state - - pid - - - Integer value. The same value as that used in the prior - - Cue Recording - - or - - Cue and Start Recording - - operation. - - - serial