diff --git a/audiohandler.cpp b/audiohandler.cpp index fa45b54..aa6d380 100644 --- a/audiohandler.cpp +++ b/audiohandler.cpp @@ -131,7 +131,7 @@ bool audioHandler::init(const quint8 bits, const quint8 channels, const quint16 isInitialized = setDevice(QAudioDeviceInfo::defaultInputDevice()); else isInitialized = setDevice(QAudioDeviceInfo::defaultOutputDevice()); - + return isInitialized; } @@ -172,11 +172,9 @@ bool audioHandler::setDevice(QAudioDeviceInfo deviceInfo) void audioHandler::reinit() { qDebug() << this->metaObject()->className() << ": reinit() running"; - bool running = false; if (audioOutput && audioOutput->state() != QAudio::StoppedState) { - running = true; + this->stop(); } - this->stop(); // Calculate the minimum required audio buffer // This may need work depending on how it performs on other platforms. @@ -207,9 +205,7 @@ void audioHandler::reinit() connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); } - if (running) { - this->start(); - } + this->start(); this->flush(); } @@ -224,15 +220,10 @@ void audioHandler::start() if (isInput) { this->open(QIODevice::WriteOnly | QIODevice::Unbuffered); - } - else { - this->open(QIODevice::ReadOnly | QIODevice::Unbuffered); - } - - if (isInput) { audioInput->start(this); } else { + this->open(QIODevice::ReadOnly | QIODevice::Unbuffered); audioOutput->start(this); } } @@ -319,7 +310,7 @@ qint64 audioHandler::writeData(const char* data, qint64 len) if (buffer.length() > bufferSize * 4) { qWarning() << "writeData() Buffer overflow"; - buffer.clear(); // Will cause a click! + // buffer.clear(); // Will cause a click! } if (isUlaw) { @@ -402,6 +393,11 @@ void audioHandler::getBufferSize() emit sendBufferSize(audioOutput->bufferSize()); } +bool audioHandler::isChunkAvailable() +{ + return chunkAvailable; +} + void audioHandler::getNextAudioChunk(QByteArray& ret) { quint16 numSamples = radioSampleBits * 120; diff --git a/audiohandler.h b/audiohandler.h index c92b306..c6dc6c8 100644 --- a/audiohandler.h +++ b/audiohandler.h @@ -40,10 +40,9 @@ public: qint64 writeData(const char* data, qint64 len); qint64 bytesAvailable() const; bool isSequential() const; - volatile bool chunkAvailable; void incomingAudio(const QByteArray& data); void getNextAudioChunk(QByteArray &data); - + bool isChunkAvailable(); public slots: bool init(const quint8 bits, const quint8 channels, const quint16 samplerate, const quint16 bufferSize, const bool isulaw, const bool isinput); void changeBufferSize(const quint16 newSize); @@ -63,13 +62,14 @@ private: QMutex mutex; - bool isInitialized; - QAudioOutput* audioOutput; - QAudioInput* audioInput; + bool chunkAvailable; + bool isInitialized; + QAudioOutput* audioOutput; + QAudioInput* audioInput; bool isUlaw; int bufferSize; bool isInput; // Used to determine whether input or output audio - float volume; + float volume; QByteArray buffer; QAudioFormat format; diff --git a/packettypes.h b/packettypes.h index 7a81842..174060f 100644 --- a/packettypes.h +++ b/packettypes.h @@ -253,8 +253,8 @@ typedef union conninfo_packet { quint32 txsample; // 0x78 quint32 civport; // 0x7c quint32 audioport; // 0x80 - char unusedk; // 0x84 quint32 txbuffer; // 0x85 + char unusedk; // 0x84 char unusedl[7]; // 0x89 }; }; diff --git a/rigcommander.cpp b/rigcommander.cpp index 13a5b8e..6fb7df6 100644 --- a/rigcommander.cpp +++ b/rigcommander.cpp @@ -86,7 +86,22 @@ void rigCommander::commSetup(unsigned char rigCivAddr, QString ip, quint16 cport this->password = password; */ if (udp == Q_NULLPTR) { - udp = new udpHandler(ip, cport, sport, aport, username, password,buffer,rxsample,rxcodec,txsample,txcodec); + + udp = new udpHandler(ip, cport, sport, aport, username, password, buffer, rxsample, rxcodec, txsample, txcodec); + + udpHandlerThread = new QThread(this); + + udp->moveToThread(udpHandlerThread); + + connect(this, SIGNAL(initUdpHandler()), udp, SLOT(init())); + connect(udpHandlerThread, SIGNAL(finished()), udp, SLOT(deleteLater())); + + + udpHandlerThread->start(); + + emit initUdpHandler(); + + connect(udp, SIGNAL(haveDataFromPort(QByteArray)), this, SLOT(handleNewData(QByteArray))); // data from the program to the comm port: @@ -113,8 +128,9 @@ void rigCommander::closeComm() } comm = Q_NULLPTR; - if (udp != Q_NULLPTR) { - delete udp; + if (udpHandlerThread != Q_NULLPTR) { + udpHandlerThread->quit(); + udpHandlerThread->wait(); } udp = Q_NULLPTR; } @@ -1438,7 +1454,7 @@ void rigCommander::getMeters(bool transmitting) { // Nice function to just grab every meter qDebug() << __func__ << ": grabbing all metering for mode " << (transmitting==true? "transmitting":"receiving") ; - + if(transmitting) { getRFPowerMeter(); @@ -1452,6 +1468,7 @@ void rigCommander::getMeters(bool transmitting) getVdMeter(); getIDMeter(); + } void rigCommander::getSMeter() diff --git a/rigcommander.h b/rigcommander.h index d7f2f14..fe11abb 100644 --- a/rigcommander.h +++ b/rigcommander.h @@ -199,7 +199,7 @@ signals: void haveATUStatus(unsigned char status); void haveChangeBufferSize(quint16 value); void haveDataForServer(QByteArray outData); - + void initUdpHandler(); private: void setup(); @@ -237,6 +237,8 @@ private: commHandler * comm=Q_NULLPTR; udpHandler* udp=Q_NULLPTR; + QThread* udpHandlerThread = Q_NULLPTR; + void determineRigCaps(); QByteArray payloadIn; QByteArray echoPerfix; diff --git a/udphandler.cpp b/udphandler.cpp index 464434b..e035cc4 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -52,6 +52,14 @@ udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16 } } + + // Set my computer name. Should this be configurable? + compName = "wfview"; + +} + +void udpHandler::init() +{ udpBase::init(); // Perform UDP socket initialization. // Connect socket to my dataReceived function. @@ -60,17 +68,18 @@ udpHandler::udpHandler(QString ip, quint16 controlPort, quint16 civPort, quint16 /* Connect various timers */ - connect(&tokenTimer, &QTimer::timeout, this, std::bind(&udpHandler::sendToken, this, 0x05)); - connect(&areYouThereTimer, &QTimer::timeout, this, QOverload<>::of(&udpHandler::sendAreYouThere)); - connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing); - connect(&idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0)); + tokenTimer = new QTimer(); + areYouThereTimer = new QTimer(); + pingTimer = new QTimer(); + idleTimer = new QTimer(); + + connect(tokenTimer, &QTimer::timeout, this, std::bind(&udpHandler::sendToken, this, 0x05)); + connect(areYouThereTimer, &QTimer::timeout, this, QOverload<>::of(&udpHandler::sendAreYouThere)); + connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing); + connect(idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0)); // Start sending are you there packets - will be stopped once "I am here" received - areYouThereTimer.start(AREYOUTHERE_PERIOD); - - // Set my computer name. Should this be configurable? - compName = "wfview"; - + areYouThereTimer->start(AREYOUTHERE_PERIOD); } udpHandler::~udpHandler() @@ -120,11 +129,11 @@ void udpHandler::dataReceived() control_packet_t in = (control_packet_t)r.constData(); if (in->type == 0x04) { // If timer is active, stop it as they are obviously there! - if (areYouThereTimer.isActive()) { - areYouThereTimer.stop(); + if (areYouThereTimer->isActive()) { + areYouThereTimer->stop(); // send ping packets every second - pingTimer.start(PING_PERIOD); - idleTimer.start(IDLE_PERIOD); + pingTimer->start(PING_PERIOD); + idleTimer->start(IDLE_PERIOD); } } // This is "I am ready" in response to "Are you ready" so send login. @@ -166,7 +175,7 @@ void udpHandler::dataReceived() if (in->response == 0x0000) { qDebug() << this->metaObject()->className() << ": Token renewal successful"; - tokenTimer.start(TOKEN_RENEWAL); + tokenTimer->start(TOKEN_RENEWAL); gotAuthOK = true; if (!streamOpened) { @@ -178,8 +187,10 @@ void udpHandler::dataReceived() { qWarning() << this->metaObject()->className() << ": Radio rejected token renewal, performing login"; remoteId = in->sentid; - isAuthenticated = false; - sendLogin(); // Try sending login packet (didn't seem to work?) + tokRequest = in->tokrequest; + token = in->token; + // Got new token response + sendToken(0x02); // Update it. } else { @@ -200,6 +211,17 @@ void udpHandler::dataReceived() { emit haveNetworkError(radioIP.toString(), "Got radio disconnected."); qDebug() << this->metaObject()->className() << ": Got radio disconnected."; + if (streamOpened) { + // Close stream connections but keep connection open to the radio. + if (audio != Q_NULLPTR) { + delete audio; + } + + if (civ != Q_NULLPTR) { + delete civ; + } + streamOpened = false; + } } break; } @@ -220,7 +242,7 @@ void udpHandler::dataReceived() qDebug() << this->metaObject()->className() << ": Received matching token response to our request"; token = in->token; sendToken(0x02); - tokenTimer.start(TOKEN_RENEWAL); // Start token request timer + tokenTimer->start(TOKEN_RENEWAL); // Start token request timer isAuthenticated = true; } else @@ -402,7 +424,7 @@ void udpHandler::sendToken(uint8_t magic) authInnerSendSeq++; sendTrackedPacket(QByteArray::fromRawData((const char *)p.packet, sizeof(p))); - tokenTimer.start(100); // Set 100ms timer for retry (this will be cancelled if a response is received) + tokenTimer->start(100); // Set 100ms timer for retry (this will be cancelled if a response is received) return; } @@ -424,13 +446,16 @@ udpCivData::udpCivData(QHostAddress local, QHostAddress ip, quint16 civPort) /* Connect various timers */ - connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing); - connect(&idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0)); + pingTimer = new QTimer(); + idleTimer = new QTimer(); + + connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing); + connect(idleTimer, &QTimer::timeout, this, std::bind(&udpBase::sendControl, this, true, 0, 0)); // send ping packets every 100 ms (maybe change to less frequent?) - pingTimer.start(PING_PERIOD); + pingTimer->start(PING_PERIOD); // Send idle packets every 100ms, this timer will be reset everytime a non-idle packet is sent. - idleTimer.start(IDLE_PERIOD); + idleTimer->start(IDLE_PERIOD); } udpCivData::~udpCivData() { @@ -608,23 +633,25 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint sendControl(false, 0x03, 0x00); // First connect packet - connect(&pingTimer, &QTimer::timeout, this, &udpBase::sendPing); - pingTimer.start(PING_PERIOD); // send ping packets every 100ms - txAudioTimer.setTimerType(Qt::PreciseTimer); - connect(&txAudioTimer, &QTimer::timeout, this, &udpAudio::sendTxAudio); - txAudioTimer.start(TXAUDIO_PERIOD); + pingTimer = new QTimer(); + connect(pingTimer, &QTimer::timeout, this, &udpBase::sendPing); + pingTimer->start(PING_PERIOD); // send ping packets every 100ms emit setupTxAudio(txNumSamples, txChannelCount, txSampleRate, bufferSize, txIsUlawCodec, true); emit setupRxAudio(rxNumSamples, rxChannelCount, rxSampleRate, bufferSize, rxIsUlawCodec, false); - + txAudioTimer = new QTimer(); + txAudioTimer->setTimerType(Qt::PreciseTimer); + connect(txAudioTimer, &QTimer::timeout, this, &udpAudio::sendTxAudio); + txAudioTimer->start(TXAUDIO_PERIOD); } udpAudio::~udpAudio() { - if (txAudioTimer.isActive()) + if (txAudioTimer != Q_NULLPTR) { - txAudioTimer.stop(); + txAudioTimer->stop(); + delete txAudioTimer; } if (rxAudioThread) { @@ -643,11 +670,12 @@ udpAudio::~udpAudio() void udpAudio::sendTxAudio() { - if (txaudio->chunkAvailable) { + if (txaudio->isChunkAvailable()) { QByteArray audio; txaudio->getNextAudioChunk(audio); int counter = 1; int len = 0; + while (len < audio.length()) { QByteArray partial = audio.mid(len, 1364); txaudio_packet p; @@ -655,15 +683,9 @@ void udpAudio::sendTxAudio() p.len = sizeof(p)+partial.length(); p.sentid = myId; p.rcvdid = remoteId; - if (counter % 2 == 0) - { - p.ident = 0x0680; - } - else { - p.ident = 0x0681; - } + p.ident = 0x0080; // TX audio is always this? p.datalen = (quint16)qToBigEndian((quint16)partial.length()); - p.sendseq = (quint16)qToBigEndian(sendAudioSeq); // THIS IS BIG ENDIAN! + p.sendseq = (quint16)qToBigEndian((quint16)sendAudioSeq); // THIS IS BIG ENDIAN! QByteArray tx = QByteArray::fromRawData((const char*)p.packet, sizeof(p)); tx.append(partial); len = len + partial.length(); @@ -754,14 +776,19 @@ udpBase::~udpBase() udp->close(); delete udp; } - if (pingTimer.isActive()) + if (pingTimer != Q_NULLPTR) { - pingTimer.stop(); + pingTimer->stop(); + delete pingTimer; } - if (idleTimer.isActive()) + if (idleTimer != Q_NULLPTR) { - idleTimer.stop(); + idleTimer->stop(); + delete idleTimer; } + pingTimer = Q_NULLPTR; + idleTimer = Q_NULLPTR; + } // Base class! @@ -908,9 +935,6 @@ void udpBase::sendControl(bool tracked=true, quint8 type=0, quint16 seq=0) else { sendTrackedPacket(QByteArray::fromRawData((const char*)p.packet, sizeof(p))); } - if (idleTimer.isActive()) { - idleTimer.start(IDLE_PERIOD); // Reset idle counter if it's running - } return; } @@ -948,8 +972,8 @@ void udpBase::sendTrackedPacket(QByteArray d) QMutexLocker locker(&mutex); udp->writeDatagram(d, radioIP, port); - if (idleTimer.isActive()) { - idleTimer.start(IDLE_PERIOD); // Reset idle counter if it's running + if (idleTimer != Q_NULLPTR && idleTimer->isActive()) { + idleTimer->start(IDLE_PERIOD); // Reset idle counter if it's running } packetsSent++; return; diff --git a/udphandler.h b/udphandler.h index 9f96ee5..3378d14 100644 --- a/udphandler.h +++ b/udphandler.h @@ -27,7 +27,7 @@ #define TOKEN_RENEWAL 60000 #define PING_PERIOD 100 #define IDLE_PERIOD 100 -#define TXAUDIO_PERIOD 10 +#define TXAUDIO_PERIOD 5 #define AREYOUTHERE_PERIOD 500 @@ -85,9 +85,9 @@ public: void sendTrackedPacket(QByteArray d); void purgeOldEntries(); - QTimer areYouThereTimer; // Send are-you-there packets every second until a response is received. - QTimer pingTimer; // Start sending pings immediately. - QTimer idleTimer; // Start watchdog once we are connected. + QTimer* areYouThereTimer = Q_NULLPTR; // Send are-you-there packets every second until a response is received. + QTimer* pingTimer = Q_NULLPTR; // Start sending pings immediately. + QTimer* idleTimer = Q_NULLPTR; // Start watchdog once we are connected. QDateTime lastPingSentTime; uint16_t pingSendSeq = 0; @@ -169,7 +169,7 @@ private: audioHandler* txaudio=Q_NULLPTR; QThread* txAudioThread=Q_NULLPTR; - QTimer txAudioTimer; + QTimer* txAudioTimer=Q_NULLPTR; }; @@ -195,7 +195,7 @@ public slots: void receiveDataFromUserToRig(QByteArray); // This slot will send data on to void receiveFromCivStream(QByteArray); void changeBufferSize(quint16 value); - + void init(); signals: void haveDataFromPort(QByteArray data); // emit this when we have data, connect to rigcommander @@ -205,7 +205,6 @@ signals: private: - void sendAreYouThere(); void dataReceived(); @@ -244,8 +243,8 @@ private: char identa; quint32 identb; - QTimer tokenTimer; - QTimer areYouThereTimer; + QTimer* tokenTimer = Q_NULLPTR; + QTimer* areYouThereTimer = Q_NULLPTR; bool highBandwidthConnection = false; }; diff --git a/wfmain.h b/wfmain.h index 4e8751a..34df217 100644 --- a/wfmain.h +++ b/wfmain.h @@ -580,8 +580,8 @@ private: satelliteSetup *sat; udpServerSetup *srv; - udpServer *udp = Q_NULLPTR; - QThread *serverThread = Q_NULLPTR; + udpServer* udp = Q_NULLPTR; + QThread* serverThread = Q_NULLPTR; void bandStackBtnClick(); bool waitingForBandStackRtn;