diff --git a/packettypes.h b/packettypes.h index c8e4c60..f2f46af 100644 --- a/packettypes.h +++ b/packettypes.h @@ -14,7 +14,7 @@ #define RETRANSMIT_PERIOD 100 // How often to attempt retransmit #define LOCK_PERIOD 10 // How long to try to lock mutex (ms) #define STALE_CONNECTION 15 // Not heard from in this many seconds -#define BUFSIZE 50 // Number of packets to buffer +#define BUFSIZE 500 // Number of packets to buffer #define TXAUDIO_PERIOD 20 diff --git a/servermain.cpp b/servermain.cpp index 2ab49e8..fd34fc5 100644 --- a/servermain.cpp +++ b/servermain.cpp @@ -48,14 +48,16 @@ servermain::servermain(const QString serialPortCL, const QString hostCL, const Q servermain::~servermain() { - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (radio.rigThread != Q_NULLPTR) + if (radio->rigThread != Q_NULLPTR) { - radio.rigThread->quit(); - radio.rigThread->wait(); + radio->rigThread->quit(); + radio->rigThread->wait(); } + delete radio; // This has been created by new in loadSettings(); } + serverConfig.rigs.clear(); if (serverThread != Q_NULLPTR) { serverThread->quit(); serverThread->wait(); @@ -79,26 +81,14 @@ void servermain::openRig() makeRig(); - if( (prefs.serialPortRadio.toLower() == QString("auto")) && (serialPortCL.isEmpty())) - { - findSerialPort(); - - } else { - if(serialPortCL.isEmpty()) - { - serialPortRig = prefs.serialPortRadio; - } else { - serialPortRig = serialPortCL; - } - } - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { //qInfo(logSystem()) << "Opening rig"; - if (radio.rigThread != Q_NULLPTR) + if (radio->rigThread != Q_NULLPTR) { //qInfo(logSystem()) << "Got rig"; - QMetaObject::invokeMethod(radio.rig, [=]() { - radio.rig->commSetup(radio.civAddr, radio.serialPort, radio.baudRate, QString("none")); + QMetaObject::invokeMethod(radio->rig, [=]() { + radio->rig->commSetup(radio->civAddr, radio->serialPort, radio->baudRate, QString("none")); }, Qt::QueuedConnection); } } @@ -106,49 +96,49 @@ void servermain::openRig() void servermain::makeRig() { - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (radio.rigThread == Q_NULLPTR) + if (radio->rigThread == Q_NULLPTR) { qInfo(logSystem()) << "Creating new rigThread()"; - radio.rig = new rigCommander(radio.guid); - radio.rigThread = new QThread(this); + radio->rig = new rigCommander(radio->guid); + radio->rigThread = new QThread(this); // Thread: - radio.rig->moveToThread(radio.rigThread); - connect(radio.rigThread, SIGNAL(started()), radio.rig, SLOT(process())); - connect(radio.rigThread, SIGNAL(finished()), radio.rig, SLOT(deleteLater())); - radio.rigThread->start(); + radio->rig->moveToThread(radio->rigThread); + connect(radio->rigThread, SIGNAL(started()), radio->rig, SLOT(process())); + connect(radio->rigThread, SIGNAL(finished()), radio->rig, SLOT(deleteLater())); + radio->rigThread->start(); // Rig status and Errors: - connect(radio.rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); - connect(radio.rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); + connect(radio->rig, SIGNAL(haveSerialPortError(QString, QString)), this, SLOT(receiveSerialPortError(QString, QString))); + connect(radio->rig, SIGNAL(haveStatusUpdate(networkStatus)), this, SLOT(receiveStatusUpdate(networkStatus))); // Rig comm setup: - //connect(this, SIGNAL(sendCommSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString)), radio.rig, SLOT(commSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString))); - //connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32, QString)), radio.rig, SLOT(commSetup(unsigned char, QString, quint32, QString))); - connect(this, SIGNAL(setRTSforPTT(bool)), radio.rig, SLOT(setRTSforPTT(bool))); + //connect(this, SIGNAL(sendCommSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString)), radio->rig, SLOT(commSetup(unsigned char, udpPreferences, audioSetup, audioSetup, QString))); + //connect(this, SIGNAL(sendCommSetup(unsigned char, QString, quint32, QString)), radio->rig, SLOT(commSetup(unsigned char, QString, quint32, QString))); + connect(this, SIGNAL(setRTSforPTT(bool)), radio->rig, SLOT(setRTSforPTT(bool))); - connect(radio.rig, SIGNAL(haveBaudRate(quint32)), this, SLOT(receiveBaudRate(quint32))); + connect(radio->rig, SIGNAL(haveBaudRate(quint32)), this, SLOT(receiveBaudRate(quint32))); - connect(this, SIGNAL(sendCloseComm()), radio.rig, SLOT(closeComm())); - connect(this, SIGNAL(sendChangeLatency(quint16)), radio.rig, SLOT(changeLatency(quint16))); - //connect(this, SIGNAL(getRigCIV()), radio.rig, SLOT(findRigs())); - //connect(this, SIGNAL(setRigID(unsigned char)), radio.rig, SLOT(setRigID(unsigned char))); - connect(radio.rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); - connect(radio.rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); + connect(this, SIGNAL(sendCloseComm()), radio->rig, SLOT(closeComm())); + connect(this, SIGNAL(sendChangeLatency(quint16)), radio->rig, SLOT(changeLatency(quint16))); + //connect(this, SIGNAL(getRigCIV()), radio->rig, SLOT(findRigs())); + //connect(this, SIGNAL(setRigID(unsigned char)), radio->rig, SLOT(setRigID(unsigned char))); + connect(radio->rig, SIGNAL(discoveredRigID(rigCapabilities)), this, SLOT(receiveFoundRigID(rigCapabilities))); + connect(radio->rig, SIGNAL(commReady()), this, SLOT(receiveCommReady())); - connect(this, SIGNAL(requestRigState()), radio.rig, SLOT(sendState())); - connect(this, SIGNAL(stateUpdated()), radio.rig, SLOT(stateUpdated())); - connect(radio.rig, SIGNAL(stateInfo(rigstate*)), this, SLOT(receiveStateInfo(rigstate*))); + connect(this, SIGNAL(requestRigState()), radio->rig, SLOT(sendState())); + connect(this, SIGNAL(stateUpdated()), radio->rig, SLOT(stateUpdated())); + connect(radio->rig, SIGNAL(stateInfo(rigstate*)), this, SLOT(receiveStateInfo(rigstate*))); //Other connections - connect(this, SIGNAL(setCIVAddr(unsigned char)), radio.rig, SLOT(setCIVAddr(unsigned char))); + connect(this, SIGNAL(setCIVAddr(unsigned char)), radio->rig, SLOT(setCIVAddr(unsigned char))); - connect(radio.rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool))); - connect(this, SIGNAL(setPTT(bool)), radio.rig, SLOT(setPTT(bool))); - connect(this, SIGNAL(getPTT()), radio.rig, SLOT(getPTT())); - connect(this, SIGNAL(getDebug()), radio.rig, SLOT(getDebug())); - if (radio.rigThread->isRunning()) { + connect(radio->rig, SIGNAL(havePTTStatus(bool)), this, SLOT(receivePTTstatus(bool))); + connect(this, SIGNAL(setPTT(bool)), radio->rig, SLOT(setPTT(bool))); + connect(this, SIGNAL(getPTT()), radio->rig, SLOT(getPTT())); + connect(this, SIGNAL(getDebug()), radio->rig, SLOT(getDebug())); + if (radio->rigThread->isRunning()) { qInfo(logSystem()) << "Rig thread is running"; } else { @@ -163,15 +153,15 @@ void servermain::makeRig() void servermain::removeRig() { - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (radio.rigThread != Q_NULLPTR) + if (radio->rigThread != Q_NULLPTR) { - radio.rigThread->disconnect(); - radio.rig->disconnect(); - delete radio.rigThread; - delete radio.rig; - radio.rig = Q_NULLPTR; + radio->rigThread->disconnect(); + radio->rig->disconnect(); + delete radio->rigThread; + delete radio->rig; + radio->rig = Q_NULLPTR; } } } @@ -242,28 +232,28 @@ void servermain::receiveCommReady() // Use the GUID to determine which radio the response is from - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (sender != Q_NULLPTR && radio.rig != Q_NULLPTR && !memcmp(sender->getGUID(), radio.guid, sizeof(radio.guid))) + if (sender != Q_NULLPTR && radio->rig != Q_NULLPTR && !memcmp(sender->getGUID(), radio->guid, sizeof(radio->guid))) { qInfo(logSystem()) << "Received CommReady!! "; - if (radio.civAddr == 0) + if (radio->civAddr == 0) { // tell rigCommander to broadcast a request for all rig IDs. // qInfo(logSystem()) << "Beginning search from wfview for rigCIV (auto-detection broadcast)"; - if (!radio.rigAvailable) { - QMetaObject::invokeMethod(radio.rig, [=]() { - radio.rig->findRigs(); + if (!radio->rigAvailable) { + QMetaObject::invokeMethod(radio->rig, [=]() { + radio->rig->findRigs(); }, Qt::QueuedConnection); } } else { // don't bother, they told us the CIV they want, stick with it. // We still query the rigID to find the model, but at least we know the CIV. - qInfo(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << radio.civAddr; - QMetaObject::invokeMethod(radio.rig, [=]() { - radio.rig->setRigID(radio.civAddr); + qInfo(logSystem()) << "Skipping automatic CIV, using user-supplied value of " << radio->civAddr; + QMetaObject::invokeMethod(radio->rig, [=]() { + radio->rig->setRigID(radio->civAddr); }, Qt::QueuedConnection); } } @@ -279,10 +269,10 @@ void servermain::receiveFoundRigID(rigCapabilities rigCaps) rigCommander* sender = qobject_cast(QObject::sender()); // Use the GUID to determine which radio the response is from - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (sender != Q_NULLPTR && radio.rig != Q_NULLPTR && !radio.rigAvailable && !memcmp(sender->getGUID(), radio.guid, sizeof(radio.guid))) + if (sender != Q_NULLPTR && radio->rig != Q_NULLPTR && !radio->rigAvailable && !memcmp(sender->getGUID(), radio->guid, sizeof(radio->guid))) { qDebug(logSystem()) << "Rig name: " << rigCaps.modelName; @@ -309,7 +299,7 @@ void servermain::receiveFoundRigID(rigCapabilities rigCaps) .arg(rigCaps.guid[14], 2, 16, QLatin1Char('0')) .arg(rigCaps.guid[15], 2, 16, QLatin1Char('0')) ; - radio.rigCaps = rigCaps; + radio->rigCaps = rigCaps; // Added so that server receives rig capabilities. emit sendRigCaps(rigCaps); } @@ -372,7 +362,7 @@ void servermain::setServerToPrefs() udp = Q_NULLPTR; } - udp = new udpServer(&serverConfig, serverTxSetup, serverRxSetup); + udp = new udpServer(serverConfig, serverTxSetup, serverRxSetup); serverThread = new QThread(this); @@ -385,15 +375,15 @@ void servermain::setServerToPrefs() // Step through all radios and connect them to the server, // server will then use GUID to determine which actual radio it belongs to. - for (RIGCONFIG& radio : serverConfig.rigs) + for (RIGCONFIG* radio : serverConfig.rigs) { - if (radio.rigThread != Q_NULLPTR) + if (radio->rigThread != Q_NULLPTR) { - if (radio.rig != Q_NULLPTR) { - connect(radio.rig, SIGNAL(haveAudioData(audioPacket)), udp, SLOT(receiveAudioData(audioPacket))); - connect(radio.rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray))); - //connect(udp, SIGNAL(haveDataFromServer(QByteArray)), radio.rig, SLOT(dataFromServer(QByteArray))); + if (radio->rig != Q_NULLPTR) { + connect(radio->rig, SIGNAL(haveAudioData(audioPacket)), udp, SLOT(receiveAudioData(audioPacket))); + connect(radio->rig, SIGNAL(haveDataForServer(QByteArray)), udp, SLOT(dataForServer(QByteArray))); + //connect(udp, SIGNAL(haveDataFromServer(QByteArray)), radio->rig, SLOT(dataFromServer(QByteArray))); connect(this, SIGNAL(sendRigCaps(rigCapabilities)), udp, SLOT(receiveRigCaps(rigCapabilities))); } } @@ -508,21 +498,21 @@ void servermain::loadSettings() else { settings->setArrayIndex(i); } - RIGCONFIG tempPrefs; - tempPrefs.civAddr = (unsigned char)settings->value("RigCIVuInt", defPrefs.radioCIVAddr).toInt(); - tempPrefs.forceRTSasPTT = (bool)settings->value("ForceRTSasPTT", defPrefs.forceRTSasPTT).toBool(); - tempPrefs.serialPort = settings->value("SerialPortRadio", defPrefs.serialPortRadio).toString(); - tempPrefs.rigName = settings->value("RigName", "").toString(); - tempPrefs.baudRate = (quint32)settings->value("SerialPortBaud", defPrefs.serialPortBaud).toInt(); + RIGCONFIG* tempPrefs = new RIGCONFIG(); + tempPrefs->civAddr = (unsigned char)settings->value("RigCIVuInt", defPrefs.radioCIVAddr).toInt(); + tempPrefs->forceRTSasPTT = (bool)settings->value("ForceRTSasPTT", defPrefs.forceRTSasPTT).toBool(); + tempPrefs->serialPort = settings->value("SerialPortRadio", defPrefs.serialPortRadio).toString(); + tempPrefs->rigName = settings->value("RigName", "").toString(); + tempPrefs->baudRate = (quint32)settings->value("SerialPortBaud", defPrefs.serialPortBaud).toInt(); - if (tempPrefs.rigName=="") + if (tempPrefs->rigName=="") { foreach(const QSerialPortInfo & serialPortInfo, QSerialPortInfo::availablePorts()) { //qInfo(logSystem()) << "Serial Port found: " << serialPortInfo.portName() << "Manufacturer:" << serialPortInfo.manufacturer() << "Product ID" << serialPortInfo.description() << "S/N" << serialPortInfo.serialNumber(); - if (serialPortInfo.portName() == tempPrefs.serialPort && !serialPortInfo.serialNumber().isEmpty()) + if (serialPortInfo.portName() == tempPrefs->serialPort && !serialPortInfo.serialNumber().isEmpty()) { - tempPrefs.rigName = serialPortInfo.serialNumber(); + tempPrefs->rigName = serialPortInfo.serialNumber(); } } } @@ -531,30 +521,33 @@ void servermain::loadSettings() guid = QUuid::createUuid().toString(); settings->setValue("GUID", guid); } - memcpy(tempPrefs.guid, QUuid::fromString(guid).toRfc4122().constData(), sizeof(tempPrefs.guid)); + memcpy(tempPrefs->guid, QUuid::fromString(guid).toRfc4122().constData(), sizeof(tempPrefs->guid)); - tempPrefs.rxAudioSetup.isinput = true; - tempPrefs.txAudioSetup.isinput = false; - tempPrefs.rxAudioSetup.localAFgain = 255; - tempPrefs.txAudioSetup.localAFgain = 255; - tempPrefs.rxAudioSetup.resampleQuality = 4; - tempPrefs.txAudioSetup.resampleQuality = 4; - - tempPrefs.rxAudioSetup.name = settings->value("AudioInput", "").toString(); - tempPrefs.txAudioSetup.name = settings->value("AudioOutput", "").toString(); + tempPrefs->rxAudioSetup.isinput = true; + tempPrefs->txAudioSetup.isinput = false; + tempPrefs->rxAudioSetup.localAFgain = 255; + tempPrefs->txAudioSetup.localAFgain = 255; + tempPrefs->rxAudioSetup.resampleQuality = 4; + tempPrefs->txAudioSetup.resampleQuality = 4; + tempPrefs->rxAudioSetup.name = settings->value("AudioInput", "").toString(); + tempPrefs->txAudioSetup.name = settings->value("AudioOutput", "").toString(); + bool rxDeviceFound = false; + bool txDeviceFound = false; // Find the actual audio devices #if defined(RTAUDIO) for (unsigned int i = 1; i < devices; i++) { info = audio->getDeviceInfo(i); if (info.outputChannels > 0) { - if (tempPrefs.txAudio.name == info->name) { - tempPrefs.txAudio.port = i; + if (tempPrefs->txAudio.name == info->name) { + tempPrefs->txAudio.port = i; + txDeviceFound = true; } } if (info.inputChannels > 0) { - if (tempPrefs.rxAudio.name == info->name) { - tempPrefs.rxAudio.port = i; + if (tempPrefs->rxAudio.name == info->name) { + tempPrefs->rxAudio.port = i; + rxDeviceFound = true; } } } @@ -563,14 +556,16 @@ void servermain::loadSettings() { info = Pa_GetDeviceInfo(i); if (info->maxInputChannels > 0) { - if (tempPrefs.txAudio.name == info->name) { - tempPrefs.txAudio.port = i; + if (tempPrefs->txAudio.name == info->name) { + tempPrefs->txAudio.port = i; + txDeviceFound = true; } } if (info->maxOutputChannels > 0) { - if (tempPrefs.rxAudio.name == info->name) { - tempPrefs.rxAudio.port = i; - } + if (tempPrefs->rxAudio.name == info->name) { + tempPrefs->rxAudio.port = i; + rxDeviceFound = true; + } } } #else @@ -581,20 +576,29 @@ void servermain::loadSettings() //qInfo(logAudio()) << "Looking for audio output devices"; for (const QAudioDeviceInfo& deviceInfo : audioOutputs) { - if (deviceInfo.deviceName() == tempPrefs.txAudioSetup.name) { - tempPrefs.txAudioSetup.port = deviceInfo; + if (deviceInfo.deviceName() == tempPrefs->txAudioSetup.name) { + tempPrefs->txAudioSetup.port = deviceInfo; + txDeviceFound = true; } } //qInfo(logAudio()) << "Looking for audio input devices"; for (const QAudioDeviceInfo& deviceInfo : audioInputs) { - if (deviceInfo.deviceName() == tempPrefs.rxAudioSetup.name) { - tempPrefs.rxAudioSetup.port = deviceInfo; + if (deviceInfo.deviceName() == tempPrefs->rxAudioSetup.name) { + tempPrefs->rxAudioSetup.port = deviceInfo; + rxDeviceFound = true; } } #endif - tempPrefs.rig = Q_NULLPTR; - tempPrefs.rigThread = Q_NULLPTR; + + if (!txDeviceFound) { + qInfo() << "Cannot find txAudioDevice" << tempPrefs->txAudioSetup.name; + } + if (!rxDeviceFound) { + qInfo() << "Cannot find rxAudioDevice" << tempPrefs->rxAudioSetup.name; + } + tempPrefs->rig = Q_NULLPTR; + tempPrefs->rigThread = Q_NULLPTR; serverConfig.rigs.append(tempPrefs); if (tempNum == 0) { settings->endGroup(); diff --git a/udphandler.cpp b/udphandler.cpp index 870e568..88e449b 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -1246,7 +1246,6 @@ void udpBase::dataReceived(QByteArray r) } else { - //std::sort(rxSeqBuf.begin(), rxSeqBuf.end()); if (in->seq < rxSeqBuf.firstKey()) { qInfo(logUdp()) << this->metaObject()->className() << ": ******* seq number has rolled over ****** previous highest: " << hex << rxSeqBuf.lastKey() << " current: " << hex << in->seq; @@ -1261,10 +1260,43 @@ void udpBase::dataReceived(QByteArray r) if (!rxSeqBuf.contains(in->seq)) { // Add incoming packet to the received buffer and if it is in the missing buffer, remove it. - rxSeqBuf.insert(in->seq, QTime::currentTime()); - if (rxSeqBuf.size() > BUFSIZE) - { - rxSeqBuf.erase(rxSeqBuf.begin()); + + + if (in->seq > rxSeqBuf.lastKey() + 1) { + // We are likely missing packets then! + missingMutex.lock(); + int missCounter = 0; + for (quint16 f = rxSeqBuf.lastKey() + 1; f < in->seq; f++) + { + if (missCounter > 50) { + // More than 50 packets missing, something horrific has happened! + qDebug(logUdp()) << "Too many missing packets, full reset!"; + rxSeqBuf.clear(); + rxMissing.clear(); + missingMutex.unlock(); + break; + } + qDebug(logUdp()) << "Detected missing packet" << f; + + if (rxSeqBuf.size() > BUFSIZE) + { + rxSeqBuf.erase(rxSeqBuf.begin()); + } + rxSeqBuf.insert(f, QTime::currentTime()); + if (!rxMissing.contains(f)) + { + rxMissing.insert(f, 0); + } + } + missingMutex.unlock(); + } + else { + if (rxSeqBuf.size() > BUFSIZE) + { + rxSeqBuf.erase(rxSeqBuf.begin()); + } + rxSeqBuf.insert(in->seq, QTime::currentTime()); + } } else { diff --git a/udpserver.cpp b/udpserver.cpp index 11ddee5..9d111f5 100644 --- a/udpserver.cpp +++ b/udpserver.cpp @@ -4,8 +4,8 @@ #define STALE_CONNECTION 15 #define LOCK_PERIOD 10 // time to attempt to lock Mutex in ms #define AUDIO_SEND_PERIOD 20 // -udpServer::udpServer(SERVERCONFIG* config, audioSetup outAudio, audioSetup inAudio) : - config(*config), +udpServer::udpServer(SERVERCONFIG& config, audioSetup outAudio, audioSetup inAudio) : + config(config), outAudio(outAudio), inAudio(inAudio) { @@ -15,29 +15,29 @@ udpServer::udpServer(SERVERCONFIG* config, audioSetup outAudio, audioSetup inAud void udpServer::init() { - for (RIGCONFIG rig : config.rigs) + for (RIGCONFIG* rig : config.rigs) { - qDebug(logUdpServer()) << "CIV:" << rig.civAddr; - qDebug(logUdpServer()) << "Model:" << rig.modelName; - qDebug(logUdpServer()) << "Name:" << rig.rigName; - qDebug(logUdpServer()) << "CIV:" << rig.civAddr; + qDebug(logUdpServer()) << "CIV:" << rig->civAddr; + qDebug(logUdpServer()) << "Model:" << rig->modelName; + qDebug(logUdpServer()) << "Name:" << rig->rigName; + qDebug(logUdpServer()) << "CIV:" << rig->civAddr; qDebug(logUdpServer()).noquote() << QString("GUID: {%1%2%3%4-%5%6-%7%8-%9%10-%11%12%13%14%15%16}") - .arg(rig.guid[0], 2, 16, QLatin1Char('0')) - .arg(rig.guid[1], 2, 16, QLatin1Char('0')) - .arg(rig.guid[2], 2, 16, QLatin1Char('0')) - .arg(rig.guid[3], 2, 16, QLatin1Char('0')) - .arg(rig.guid[4], 2, 16, QLatin1Char('0')) - .arg(rig.guid[5], 2, 16, QLatin1Char('0')) - .arg(rig.guid[6], 2, 16, QLatin1Char('0')) - .arg(rig.guid[7], 2, 16, QLatin1Char('0')) - .arg(rig.guid[8], 2, 16, QLatin1Char('0')) - .arg(rig.guid[9], 2, 16, QLatin1Char('0')) - .arg(rig.guid[10], 2, 16, QLatin1Char('0')) - .arg(rig.guid[11], 2, 16, QLatin1Char('0')) - .arg(rig.guid[12], 2, 16, QLatin1Char('0')) - .arg(rig.guid[13], 2, 16, QLatin1Char('0')) - .arg(rig.guid[14], 2, 16, QLatin1Char('0')) - .arg(rig.guid[15], 2, 16, QLatin1Char('0')) + .arg(rig->guid[0], 2, 16, QLatin1Char('0')) + .arg(rig->guid[1], 2, 16, QLatin1Char('0')) + .arg(rig->guid[2], 2, 16, QLatin1Char('0')) + .arg(rig->guid[3], 2, 16, QLatin1Char('0')) + .arg(rig->guid[4], 2, 16, QLatin1Char('0')) + .arg(rig->guid[5], 2, 16, QLatin1Char('0')) + .arg(rig->guid[6], 2, 16, QLatin1Char('0')) + .arg(rig->guid[7], 2, 16, QLatin1Char('0')) + .arg(rig->guid[8], 2, 16, QLatin1Char('0')) + .arg(rig->guid[9], 2, 16, QLatin1Char('0')) + .arg(rig->guid[10], 2, 16, QLatin1Char('0')) + .arg(rig->guid[11], 2, 16, QLatin1Char('0')) + .arg(rig->guid[12], 2, 16, QLatin1Char('0')) + .arg(rig->guid[13], 2, 16, QLatin1Char('0')) + .arg(rig->guid[14], 2, 16, QLatin1Char('0')) + .arg(rig->guid[15], 2, 16, QLatin1Char('0')) ; } srand(time(NULL)); // Generate random key @@ -85,13 +85,6 @@ void udpServer::init() udpAudio->bind(config.audioPort); QUdpSocket::connect(udpAudio, &QUdpSocket::readyRead, this, &udpServer::audioReceived); -#if !defined(PORTAUDIO) && !defined(RTAUDIO) - qInfo(logUdpServer()) << "Server audio input (RX):" << inAudio.port.deviceName(); - qInfo(logUdpServer()) << "Server audio output (TX):" << outAudio.port.deviceName(); -#else - qInfo(logUdpServer()) << "Server audio input (RX):" << inAudio.name; - qInfo(logUdpServer()) << "Server audio output (TX):" << outAudio.name; -#endif wdTimer = new QTimer(); connect(wdTimer, &QTimer::timeout, this, &udpServer::watchdog); wdTimer->start(500); @@ -137,14 +130,14 @@ udpServer::~udpServer() void udpServer::receiveRigCaps(rigCapabilities caps) { - for (RIGCONFIG &rig: config.rigs) { - if (!memcmp(rig.guid, caps.guid, sizeof(rig.guid))) { + for (RIGCONFIG* rig: config.rigs) { + if (!memcmp(rig->guid, caps.guid, sizeof(rig->guid))) { // Matching rig, fill-in missing details - rig.rigAvailable = true; - rig.modelName = caps.modelName; - rig.civAddr = caps.civ; - if (rig.rigName=="") { - rig.rigName = caps.modelName; + rig->rigAvailable = true; + rig->modelName = caps.modelName; + rig->civAddr = caps.civ; + if (rig->rigName=="") { + rig->rigName = caps.modelName; } } } @@ -267,8 +260,8 @@ void udpServer::controlReceived() // Request for new token qInfo(logUdpServer()) << current->ipAddress.toString() << ": Received create token request"; sendCapabilities(current); - for (RIGCONFIG& radio : config.rigs) { - sendConnectionInfo(current, radio.guid); + for (RIGCONFIG* radio : config.rigs) { + sendConnectionInfo(current, radio->guid); } } else if (in->res == 0x01) { @@ -280,10 +273,10 @@ void udpServer::controlReceived() // Disconnect audio/civ sendTokenResponse(current, in->res); current->isStreaming = false; - for (RIGCONFIG& radio : config.rigs) { - if (!memcmp(radio.guid, current->guid, sizeof(radio.guid))) + for (RIGCONFIG* radio : config.rigs) { + if (!memcmp(radio->guid, current->guid, sizeof(radio->guid))) { - sendConnectionInfo(current, radio.guid); + sendConnectionInfo(current, radio->guid); } } } @@ -350,68 +343,71 @@ void udpServer::controlReceived() " txSampleRate" << current->txSampleRate << " txBufferLen" << current->txBufferLen; - if (!config.lan) { - // Radio is connected by USB/Serial and we assume that audio is connected as well. - // Create audio TX/RX threads if they don't already exist (first client chooses samplerate/codec) - audioSetup setup; - setup.resampleQuality = config.resampleQuality; - for (RIGCONFIG& radio : config.rigs) { - if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)) && radio.txaudio == Q_NULLPTR) - { - radio.txAudioSetup.codec = current->txCodec; - radio.txAudioSetup.samplerate = current->txSampleRate; - radio.txAudioSetup.isinput = false; - radio.txAudioSetup.latency = current->txBufferLen; - outAudio.isinput = false; + audioSetup setup; + setup.resampleQuality = config.resampleQuality; + for (RIGCONFIG* radio : config.rigs) { + if (!memcmp(radio->guid, current->guid, sizeof(radio->guid)) && radio->txaudio == Q_NULLPTR) + { + radio->txAudioSetup.codec = current->txCodec; + radio->txAudioSetup.samplerate = current->txSampleRate; + radio->txAudioSetup.isinput = false; + radio->txAudioSetup.latency = current->txBufferLen; + outAudio.isinput = false; - radio.txaudio = new audioHandler(); - radio.txAudioThread = new QThread(this); + radio->txaudio = new audioHandler(); + radio->txAudioThread = new QThread(this); - radio.txaudio->moveToThread(radio.txAudioThread); + radio->txaudio->moveToThread(radio->txAudioThread); - radio.txAudioThread->start(QThread::TimeCriticalPriority); + radio->txAudioThread->start(QThread::TimeCriticalPriority); - //connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup))); - connect(radio.txAudioThread, SIGNAL(finished()), radio.txaudio, SLOT(deleteLater())); + //connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup))); + connect(radio->txAudioThread, SIGNAL(finished()), radio->txaudio, SLOT(deleteLater())); - QMetaObject::invokeMethod(radio.txaudio, [=]() { - radio.txaudio->init(radio.txAudioSetup); - }, Qt::QueuedConnection); + QMetaObject::invokeMethod(radio->txaudio, [=]() { + radio->txaudio->init(radio->txAudioSetup); + }, Qt::QueuedConnection); - emit setupTxAudio(outAudio); - hasTxAudio = datagram.senderAddress(); + emit setupTxAudio(outAudio); + hasTxAudio = datagram.senderAddress(); - connect(this, SIGNAL(haveAudioData(audioPacket)), radio.txaudio, SLOT(incomingAudio(audioPacket))); + connect(this, SIGNAL(haveAudioData(audioPacket)), radio->txaudio, SLOT(incomingAudio(audioPacket))); - } - if (!memcmp(radio.guid, current->guid, sizeof(radio.guid)) && radio.rxaudio == Q_NULLPTR) - { - radio.rxAudioSetup.codec = current->rxCodec; - radio.rxAudioSetup.samplerate = current->rxSampleRate; - radio.rxAudioSetup.latency = current->txBufferLen; - radio.rxAudioSetup.isinput = true; + } + if (!memcmp(radio->guid, current->guid, sizeof(radio->guid)) && radio->rxaudio == Q_NULLPTR) + { + #if !defined(PORTAUDIO) && !defined(RTAUDIO) + qInfo(logUdpServer()) << "Radio" << radio->rigName << "audio input(RX) :" << radio->rxAudioSetup.port.deviceName(); + qInfo(logUdpServer()) << "Radio" << radio->rigName << "audio output(TX) :" << radio->txAudioSetup.port.deviceName(); + #else + qInfo(logUdpServer()) << "Server audio input (RX):" << inAudio.name; + qInfo(logUdpServer()) << "Server audio output (TX):" << outAudio.name; + #endif - radio.rxaudio = new audioHandler(); + radio->rxAudioSetup.codec = current->rxCodec; + radio->rxAudioSetup.samplerate = current->rxSampleRate; + radio->rxAudioSetup.latency = current->txBufferLen; + radio->rxAudioSetup.isinput = true; - radio.rxAudioThread = new QThread(this); + radio->rxaudio = new audioHandler(); - radio.rxaudio->moveToThread(radio.rxAudioThread); + radio->rxAudioThread = new QThread(this); - radio.rxAudioThread->start(QThread::TimeCriticalPriority); + radio->rxaudio->moveToThread(radio->rxAudioThread); - //connect(this, SIGNAL(setupRxAudio(audioSetup)), rxaudio, SLOT(init(audioSetup))); - connect(radio.rxAudioThread, SIGNAL(finished()), radio.rxaudio, SLOT(deleteLater())); + radio->rxAudioThread->start(QThread::TimeCriticalPriority); - QMetaObject::invokeMethod(radio.rxaudio, [=]() { - radio.rxaudio->init(radio.rxAudioSetup); - }, Qt::QueuedConnection); + connect(radio->rxAudioThread, SIGNAL(finished()), radio->rxaudio, SLOT(deleteLater())); - radio.rxAudioTimer = new QTimer(); - radio.rxAudioTimer->setTimerType(Qt::PreciseTimer); - connect(radio.rxAudioTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRxAudio, this)); - radio.rxAudioTimer->start(TXAUDIO_PERIOD); - } + QMetaObject::invokeMethod(radio->rxaudio, [=]() { + radio->rxaudio->init(radio->rxAudioSetup); + }, Qt::QueuedConnection); + + radio->rxAudioTimer = new QTimer(); + radio->rxAudioTimer->setTimerType(Qt::PreciseTimer); + connect(radio->rxAudioTimer, &QTimer::timeout, this, std::bind(&udpServer::sendRxAudio, this)); + radio->rxAudioTimer->start(TXAUDIO_PERIOD); } } @@ -568,12 +564,12 @@ void udpServer::civReceived() qDebug(logUdpServer()) << current->ipAddress.toString() << ": Detected invalid remote CI-V:" << hex << (quint8)r[lastFE+2]; } - for (RIGCONFIG& radio : config.rigs) { - if (!memcmp(radio.guid, current->guid, sizeof(radio.guid))) + for (RIGCONFIG* radio : config.rigs) { + if (!memcmp(radio->guid, current->guid, sizeof(radio->guid))) { // Only send to the rig that it belongs to! - QMetaObject::invokeMethod(radio.rig, [=]() { - radio.rig->dataFromServer(r.mid(0x15));; + QMetaObject::invokeMethod(radio->rig, [=]() { + radio->rig->dataFromServer(r.mid(0x15));; }, Qt::DirectConnection); } } @@ -886,14 +882,53 @@ void udpServer::commonReceived(QList* l, CLIENT* current, QByteArray r) if (!current->rxSeqBuf.contains(in->seq)) { - // Add incoming packet to the received buffer and if it is in the missing buffer, remove it. if (current->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { - if (current->rxSeqBuf.size() > BUFSIZE) - { - current->rxSeqBuf.remove(current->rxSeqBuf.firstKey()); + // Add incoming packet to the received buffer and if it is in the missing buffer, remove it. + int missCounter = 0; + if (in->seq > current->rxSeqBuf.lastKey() + 1) { + // We are likely missing packets then! + if (current->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) + { + + for (quint16 f = current->rxSeqBuf.lastKey() + 1; f < in->seq; f++) + { + if (missCounter > 50) { + // More than 50 packets missing, something horrific has happened! + qDebug(logUdpServer()) << "Too many missing packets, full reset!"; + current->rxSeqBuf.clear(); + current->rxMissing.clear(); + current->missMutex.unlock(); + break; + } + + qInfo(logUdpServer()) << "Detected missing packet" << f; + + if (current->rxSeqBuf.size() > BUFSIZE) + { + current->rxSeqBuf.remove(current->rxSeqBuf.firstKey()); + } + current->rxSeqBuf.insert(f, QTime::currentTime()); + + if (!current->rxMissing.contains(f)) + { + current->rxMissing.insert(f, 0); + } + } + current->missMutex.unlock(); + } + else { + qInfo(logUdpServer()) << "Unable to lock missMutex()"; + } + } + else { + + if (current->rxSeqBuf.size() > BUFSIZE) + { + current->rxSeqBuf.remove(current->rxSeqBuf.firstKey()); + } + current->rxSeqBuf.insert(in->seq, QTime::currentTime()); } - current->rxSeqBuf.insert(in->seq, QTime::currentTime()); current->rxMutex.unlock(); } else { @@ -944,6 +979,11 @@ void udpServer::sendControl(CLIENT* c, quint8 type, quint16 seq) s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p)); if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { + if (c->txSeqBuf.size() > BUFSIZE) + { + c->txSeqBuf.remove(c->txSeqBuf.firstKey()); + } + c->txSeqBuf.insert(seq, s); c->txSeq++; c->txMutex.unlock(); @@ -1069,6 +1109,11 @@ void udpServer::sendLoginResponse(CLIENT* c, bool allowed) s.data = QByteArray::fromRawData((const char*)p.packet, sizeof(p)); if (c->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { + if (c->txSeqBuf.size() > BUFSIZE) + { + c->txSeqBuf.remove(c->txSeqBuf.firstKey()); + } + c->txSeqBuf.insert(c->txSeq, s); c->txSeq++; c->txMutex.unlock(); @@ -1111,24 +1156,24 @@ void udpServer::sendCapabilities(CLIENT* c) s.timeSent = QTime::currentTime(); s.retransmitCount = 0; - for (RIGCONFIG &rig : config.rigs) { - qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Capabilities :" << c->txSeq << "for" << rig.modelName; + for (RIGCONFIG* rig : config.rigs) { + qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending Capabilities :" << c->txSeq << "for" << rig->modelName; radio_cap_packet r; memset(r.packet, 0x0, sizeof(r)); // We can't be sure it is initialized with 0x00! - memcpy(r.guid, rig.guid, sizeof(r.guid)); - memcpy(r.name, rig.rigName.toLocal8Bit(), sizeof(r.name)); + memcpy(r.guid, rig->guid, sizeof(r.guid)); + memcpy(r.name, rig->rigName.toLocal8Bit(), sizeof(r.name)); memcpy(r.audio, QByteArrayLiteral("ICOM_VAUDIO").constData(), 11); - if (rig.hasWiFi && !rig.hasEthernet) { - r.conntype = 0x0707; // 0x0707 for wifi rig. + if (rig->hasWiFi && !rig->hasEthernet) { + r.conntype = 0x0707; // 0x0707 for wifi rig-> } else { - r.conntype = 0x073f; // 0x073f for ethernet rig. + r.conntype = 0x073f; // 0x073f for ethernet rig-> } - r.civ = rig.civAddr; - r.baudrate = (quint32)qToBigEndian(rig.baudRate); + r.civ = rig->civAddr; + r.baudrate = (quint32)qToBigEndian(rig->baudRate); /* 0x80 = 12K only 0x40 = 44.1K only @@ -1139,7 +1184,7 @@ void udpServer::sendCapabilities(CLIENT* c) 0x02 = 16K only 0x01 = 8K only */ - if (rig.rxaudio == Q_NULLPTR) { + if (rig->rxaudio == Q_NULLPTR) { r.rxsample = 0x8b01; // all rx sample frequencies supported } else { @@ -1160,7 +1205,7 @@ void udpServer::sendCapabilities(CLIENT* c) } } - if (rig.txaudio == Q_NULLPTR) { + if (rig->txaudio == Q_NULLPTR) { r.txsample = 0x8b01; // all tx sample frequencies supported r.enablea = 0x01; // 0x01 enables TX 24K mode? qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Client will have TX audio"; @@ -1217,8 +1262,8 @@ void udpServer::sendCapabilities(CLIENT* c) // Also used to display currently connected used information. void udpServer::sendConnectionInfo(CLIENT* c, quint8 guid[16]) { - for (RIGCONFIG& radio : config.rigs) { - if (!memcmp(guid, radio.guid, sizeof(guid))) + for (RIGCONFIG* radio : config.rigs) { + if (!memcmp(guid, radio->guid, sizeof(guid))) { qInfo(logUdpServer()) << c->ipAddress.toString() << "(" << c->type << "): Sending ConnectionInfo :" << c->txSeq; conninfo_packet p; @@ -1232,10 +1277,10 @@ void udpServer::sendConnectionInfo(CLIENT* c, quint8 guid[16]) p.tokrequest = c->tokenRx; p.token = c->tokenTx; p.code = 0x0380; - memcpy(p.guid, radio.guid, sizeof(p.guid)); - memcpy(p.name, radio.rigName.toLocal8Bit(), sizeof(p.name)); + memcpy(p.guid, radio->guid, sizeof(p.guid)); + memcpy(p.name, radio->rigName.toLocal8Bit(), sizeof(p.name)); - if (radio.rigAvailable) { + if (radio->rigAvailable) { if (c->isStreaming) { p.busy = 0x01; } @@ -1465,7 +1510,6 @@ void udpServer::sendStatus(CLIENT* c) void udpServer::dataForServer(QByteArray d) { - rigCommander* sender = qobject_cast(QObject::sender()); if (sender == Q_NULLPTR) @@ -1479,67 +1523,63 @@ void udpServer::dataForServer(QByteArray d) { continue; } - for (RIGCONFIG& radio : config.rigs) + // Use the GUID to determine which radio the response is from + if (memcmp(sender->getGUID(), client->guid, sizeof(client->guid))) { - - if (memcmp(radio.guid, client->guid, sizeof(radio.guid))) + continue; // Rig guid doesn't match the one requested by the client. + } + + int lastFE = d.lastIndexOf((quint8)0xfe); + //qInfo(logUdpServer()) << "Server got CIV data from" << radio->rigName << "length" << d.length(); + if (client->connected && d.length() > lastFE + 2 && + ((quint8)d[lastFE + 1] == client->civId || (quint8)d[lastFE + 2] == client->civId || + (quint8)d[lastFE + 1] == 0x00 || (quint8)d[lastFE + 2] == 0x00 || (quint8)d[lastFE + 1] == 0xE1 || (quint8)d[lastFE + 2] == 0xE1)) + { + data_packet p; + memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00! + p.len = (quint16)d.length() + sizeof(p); + p.seq = client->txSeq; + p.sentid = client->myId; + p.rcvdid = client->remoteId; + p.reply = (char)0xc1; + p.datalen = (quint16)d.length(); + p.sendseq = client->innerSeq; + QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p)); + t.append(d); + + SEQBUFENTRY s; + s.seqNum = p.seq; + s.timeSent = QTime::currentTime(); + s.retransmitCount = 0; + s.data = t; + + if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { - continue; - } - - int lastFE = d.lastIndexOf((quint8)0xfe); - // Use the GUID to determine which radio the response is from - qInfo(logUdpServer()) << "Server got CIV data from" << radio.rigName << "length" << d.length(); - if (client->connected && d.length() > lastFE + 2 && - ((quint8)d[lastFE + 1] == client->civId || (quint8)d[lastFE + 2] == client->civId || - (quint8)d[lastFE + 1] == 0x00 || (quint8)d[lastFE + 2] == 0x00 || (quint8)d[lastFE + 1] == 0xE1 || (quint8)d[lastFE + 2] == 0xE1)) - { - data_packet p; - memset(p.packet, 0x0, sizeof(p)); // We can't be sure it is initialized with 0x00! - p.len = (quint16)d.length() + sizeof(p); - p.seq = client->txSeq; - p.sentid = client->myId; - p.rcvdid = client->remoteId; - p.reply = (char)0xc1; - p.datalen = (quint16)d.length(); - p.sendseq = client->innerSeq; - QByteArray t = QByteArray::fromRawData((const char*)p.packet, sizeof(p)); - t.append(d); - - SEQBUFENTRY s; - s.seqNum = p.seq; - s.timeSent = QTime::currentTime(); - s.retransmitCount = 0; - s.data = t; - - if (client->txMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) + if (client->txSeqBuf.size() > BUFSIZE) { - if (client->txSeqBuf.size() > BUFSIZE) - { - client->txSeqBuf.remove(client->txSeqBuf.firstKey()); - } - client->txSeqBuf.insert(p.seq, s); - client->txSeq++; - client->innerSeq++; - client->txMutex.unlock(); - } - else { - qInfo(logUdpServer()) << "Unable to lock txMutex()"; - } - - - if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) - { - client->socket->writeDatagram(t, client->ipAddress, client->port); - udpMutex.unlock(); - } - else { - qInfo(logUdpServer()) << "Unable to lock udpMutex()"; + client->txSeqBuf.remove(client->txSeqBuf.firstKey()); } + client->txSeqBuf.insert(p.seq, s); + client->txSeq++; + client->innerSeq++; + client->txMutex.unlock(); } else { - qInfo(logUdpServer()) << "Got data for different ID" << hex << (quint8)d[lastFE + 1] << ":" << hex << (quint8)d[lastFE + 2]; + qInfo(logUdpServer()) << "Unable to lock txMutex()"; } + + + if (udpMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) + { + client->socket->writeDatagram(t, client->ipAddress, client->port); + udpMutex.unlock(); + } + else { + qInfo(logUdpServer()) << "Unable to lock udpMutex()"; + } + } + else { + qInfo(logUdpServer()) << "Got data for different ID" << hex << (quint8)d[lastFE + 1] << ":" << hex << (quint8)d[lastFE + 2]; } } return; @@ -1548,13 +1588,13 @@ void udpServer::dataForServer(QByteArray d) void udpServer::sendRxAudio() { QByteArray audio; - for (RIGCONFIG &rig : config.rigs) { + for (RIGCONFIG* rig : config.rigs) { - if (rig.rxaudio != Q_NULLPTR) { + if (rig->rxaudio != Q_NULLPTR) { if (audioMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { audio.clear(); - rig.rxaudio->getNextAudioChunk(audio); + rig->rxaudio->getNextAudioChunk(audio); int len = 0; while (len < audio.length()) { audioPacket partial; @@ -1641,122 +1681,26 @@ void udpServer::sendRetransmitRequest(CLIENT* c) QByteArray missingSeqs; QTime missingTime = QTime::currentTime(); - if (!c->rxSeqBuf.empty() && c->rxSeqBuf.size() <= c->rxSeqBuf.lastKey() - c->rxSeqBuf.firstKey()) - { - if ((c->rxSeqBuf.lastKey() - c->rxSeqBuf.firstKey() - c->rxSeqBuf.size()) > 20) - { - // Too many packets to process, flush buffers and start again! - qDebug(logUdp()) << "Too many missing packets, flushing buffer: " << c->rxSeqBuf.lastKey() << "missing=" << c->rxSeqBuf.lastKey() - c->rxSeqBuf.firstKey() - c->rxSeqBuf.size() + 1; - if (c->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) - { - c->rxMissing.clear(); - c->missMutex.unlock(); - } - else { - qInfo(logUdpServer()) << "Unable to lock missMutex()"; - } - - if (c->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) - { - c->rxSeqBuf.clear(); - c->rxMutex.unlock(); - } - else { - qInfo(logUdpServer()) << "Unable to lock rxMutex()"; - } - - } - else { - // We have at least 1 missing packet! - qDebug(logUdp()) << "Missing Seq: size=" << c->rxSeqBuf.size() << "firstKey=" << c->rxSeqBuf.firstKey() << "lastKey=" << c->rxSeqBuf.lastKey() << "missing=" << c->rxSeqBuf.lastKey() - c->rxSeqBuf.firstKey() - c->rxSeqBuf.size() + 1; - // We are missing packets so iterate through the buffer and add the missing ones to missing packet list - if (c->rxMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) - { - if (c->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) - { - int missCounter = 0; - auto i = std::adjacent_find(c->rxSeqBuf.keys().begin(), c->rxSeqBuf.keys().end(), [](int l, int r) {return l + 1 < r; }); - while (i != c->rxSeqBuf.keys().end()) - { - quint16 j = 1 + *i; - ++i; - if (i == c->rxSeqBuf.keys().end()) - { - continue; - } - if (c->rxSeqBuf.lastKey() - c->rxSeqBuf.firstKey() - c->rxSeqBuf.size() == 0 && c->type == "AUDIO" && - (c->txCodec == 0x40 || c->txCodec == 0x80)) - { - // Single missing audio packet ignore it! - qDebug(logUdpServer()) << "Single missing audio packet will be handled by FEC (" << hex << j << ")"; - c->rxSeqBuf.insert(j, QTime::currentTime()); // Add this missing packet to the rxbuffer so it doesn't try to retransmit - c->missMutex.unlock(); - c->rxMutex.unlock(); - return; - } - - missCounter++; - - if (missCounter > 20) { - // More than 20 packets missing, something horrific has happened! - qDebug(logUdpServer()) << ": Too many missing packets, clearing buffer"; - c->rxSeqBuf.clear(); - c->rxMissing.clear(); - c->missMutex.unlock(); - c->rxMutex.unlock(); - return; - } - auto s = c->rxMissing.find(j); - if (s == c->rxMissing.end()) - { - // We haven't seen this missing packet before - qDebug(logUdp()) << this->metaObject()->className() << ": Adding to missing buffer (len=" << c->rxMissing.size() << "): " << j << dec << missingTime.msecsTo(QTime::currentTime()) << "ms"; - c->rxMissing.insert(j, 0); - - if (c->rxSeqBuf.size() > BUFSIZE) - { - c->rxSeqBuf.remove(c->rxSeqBuf.firstKey()); - } - c->rxSeqBuf.insert(j, QTime::currentTime()); // Add this missing packet to the rxbuffer as we now long about it. - } - else { - if (s.value() == 4) - { - // We have tried 4 times to request this packet, time to give up! - s = c->rxMissing.erase(s); - } - } - - } - } - else { - qInfo(logUdpServer()) << "Unable to lock missMutex()"; - } - c->rxMutex.unlock(); - } - else { - qInfo(logUdpServer()) << "Unable to lock rxMutex()"; - } - c->missMutex.unlock(); - } - } - - if (missingTime.msecsTo(QTime::currentTime()) > 10) { - qInfo(logUdpServer()) << "Initial missing processing has been running for" << missingTime.msecsTo(QTime::currentTime()) << "(ms)"; - } - if (c->missMutex.try_lock_for(std::chrono::milliseconds(LOCK_PERIOD))) { for (auto it = c->rxMissing.begin(); it != c->rxMissing.end(); ++it) { - if (it.value() < 10) + if (it.value() < 4) { missingSeqs.append(it.key() & 0xff); missingSeqs.append(it.key() >> 8 & 0xff); missingSeqs.append(it.key() & 0xff); missingSeqs.append(it.key() >> 8 & 0xff); it.value()++; + } + + else { + // We have tried 4 times to request this packet, time to give up! + qDebug(logUdp()) << this->metaObject()->className() << ": No response for missing packet" << it.key() << "deleting"; + it = c->rxMissing.erase(it); } + + } if (missingSeqs.length() != 0) @@ -1889,27 +1833,27 @@ void udpServer::deleteConnection(QList* l, CLIENT* c) } if (len == 0) { - for (RIGCONFIG& radio : config.rigs) { - if (!memcmp(radio.guid, guid, sizeof(radio.guid))) + for (RIGCONFIG* radio : config.rigs) { + if (!memcmp(radio->guid, guid, sizeof(radio->guid))) { - if (radio.rxAudioTimer != Q_NULLPTR) { - radio.rxAudioTimer->stop(); - delete radio.rxAudioTimer; - radio.rxAudioTimer = Q_NULLPTR; + if (radio->rxAudioTimer != Q_NULLPTR) { + radio->rxAudioTimer->stop(); + delete radio->rxAudioTimer; + radio->rxAudioTimer = Q_NULLPTR; } - if (radio.rxAudioThread != Q_NULLPTR) { - radio.rxAudioThread->quit(); - radio.rxAudioThread->wait(); - radio.rxaudio = Q_NULLPTR; - radio.rxAudioThread = Q_NULLPTR; + if (radio->rxAudioThread != Q_NULLPTR) { + radio->rxAudioThread->quit(); + radio->rxAudioThread->wait(); + radio->rxaudio = Q_NULLPTR; + radio->rxAudioThread = Q_NULLPTR; } - if (radio.txAudioThread != Q_NULLPTR) { - radio.txAudioThread->quit(); - radio.txAudioThread->wait(); - radio.txaudio = Q_NULLPTR; - radio.txAudioThread = Q_NULLPTR; + if (radio->txAudioThread != Q_NULLPTR) { + radio->txAudioThread->quit(); + radio->txAudioThread->wait(); + radio->txaudio = Q_NULLPTR; + radio->txAudioThread = Q_NULLPTR; } } } diff --git a/udpserver.h b/udpserver.h index 2269732..feea307 100644 --- a/udpserver.h +++ b/udpserver.h @@ -79,7 +79,7 @@ struct SERVERCONFIG { quint8 resampleQuality; quint32 baudRate; QList users; - QList rigs; + QList rigs; }; @@ -88,7 +88,7 @@ class udpServer : public QObject Q_OBJECT public: - udpServer(SERVERCONFIG* config, audioSetup outAudio, audioSetup inAudio); + udpServer(SERVERCONFIG& config, audioSetup outAudio, audioSetup inAudio); ~udpServer(); public slots: