From f00051ecd47cc998b01f3536b3326f91ec0a4c49 Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Wed, 6 Apr 2022 21:52:22 +0100 Subject: [PATCH] Use signal/slot for audio signal reporting --- audiohandler.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++- audiohandler.h | 7 +++++-- udphandler.cpp | 49 ++++++++++++++++++++++++---------------------- udphandler.h | 12 ++++++++++-- 4 files changed, 91 insertions(+), 28 deletions(-) diff --git a/audiohandler.cpp b/audiohandler.cpp index ad0939f..d6f1172 100644 --- a/audiohandler.cpp +++ b/audiohandler.cpp @@ -124,9 +124,11 @@ bool audioHandler::init(audioSetup setupIn) if (setup.isinput) { audioInput = new QAudioInput(setup.port, format, this); + connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); } else { audioOutput = new QAudioOutput(setup.port, format, this); + connect(audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); } // Setup resampler and opus if they are needed. @@ -357,7 +359,6 @@ void audioHandler::incomingAudio(audioPacket inPacket) } currentLatency = livePacket.time.msecsTo(QTime::currentTime()) + getAudioDuration(audioOutput->bufferSize()-audioOutput->bytesFree(),format); - if (audioDevice != Q_NULLPTR) { audioDevice->write(livePacket.data); } @@ -370,6 +371,8 @@ void audioHandler::incomingAudio(audioPacket inPacket) lastSentSeq = inPacket.seq; } + emit haveLevels(getAmplitude(), setup.latency, currentLatency,isUnderrun); + return; } @@ -525,6 +528,9 @@ void audioHandler::getNextAudioChunk(QByteArray& ret) } } } + + emit haveLevels(getAmplitude(), setup.latency, currentLatency, isUnderrun); + return; } @@ -555,3 +561,46 @@ quint16 audioHandler::getAmplitude() return static_cast(amplitude * 255.0); } + + +void audioHandler::stateChanged(QAudio::State state) +{ + // Process the state + switch (state) + { + case QAudio::IdleState: + { + isUnderrun = true; + break; + } + case QAudio::ActiveState: + { + //qDebug(logAudio()) << (setup.isinput ? "Input" : "Output") << "Audio started!"; + if (underTimer == Q_NULLPTR) { + underTimer = new QTimer(); + underTimer->setSingleShot(true); + connect(underTimer, &QTimer::timeout, this, &audioHandler::clearUnderrun); + underTimer->start(500); + } + break; + } + case QAudio::SuspendedState: + { + break; + } + case QAudio::StoppedState: + { + break; + } + default: { + } + break; + } +} + +void audioHandler::clearUnderrun() +{ + isUnderrun = false; + delete underTimer; + underTimer = Q_NULLPTR; +} \ No newline at end of file diff --git a/audiohandler.h b/audiohandler.h index 45b0219..e10aeac 100644 --- a/audiohandler.h +++ b/audiohandler.h @@ -95,16 +95,18 @@ public slots: void incomingAudio(const audioPacket data); private slots: + void stateChanged(QAudio::State state); + void clearUnderrun(); signals: void audioMessage(QString message); void sendLatency(quint16 newSize); void haveAudioData(const QByteArray& data); - + void haveLevels(quint16 amplitude,quint16 latency,quint16 current,bool under); private: - + bool isUnderrun = false; bool isInitialized=false; bool isReady = false; bool audioBuffered = false; @@ -140,6 +142,7 @@ private: OpusEncoder* encoder=Q_NULLPTR; OpusDecoder* decoder=Q_NULLPTR; + QTimer * underTimer=Q_NULLPTR; }; diff --git a/udphandler.cpp b/udphandler.cpp index 3fbfd41..509584b 100644 --- a/udphandler.cpp +++ b/udphandler.cpp @@ -135,6 +135,20 @@ void udpHandler::receiveDataFromUserToRig(QByteArray data) } } +void udpHandler::getRxLevels(quint16 amplitude,quint16 latency,quint16 current, bool under) { + status.rxAudioLevel = amplitude; + status.rxLatency = latency; + status.rxCurrentLatency = current; + status.rxUnderrun = under; +} + +void udpHandler::getTxLevels(quint16 amplitude,quint16 latency, quint16 current, bool under) { + status.txAudioLevel = amplitude; + status.txLatency = latency; + status.txCurrentLatency = current; + status.txUnderrun = under; +} + void udpHandler::dataReceived() { while (udp->hasPendingDatagrams()) { @@ -186,13 +200,12 @@ void udpHandler::dataReceived() } QString tempLatency; - status.rxLatency = audio->audioLatency; - if (rxSetup.latency > audio->audioLatency) + if (status.rxLatency > status.rxCurrentLatency && !status.rxUnderrun) { - tempLatency = QString("%1 ms").arg(audio->audioLatency,3); + tempLatency = QString("%1 ms").arg(status.rxCurrentLatency,3); } else { - tempLatency = QString("%1 ms").arg(audio->audioLatency,3); + tempLatency = QString("%1 ms").arg(status.rxCurrentLatency,3); } QString txString=""; if (txSetup.codec == 0) { @@ -200,10 +213,6 @@ void udpHandler::dataReceived() } status.message = QString("
%1 rx latency: %2 / rtt: %3 ms / loss: %4/%5
").arg(txString).arg(tempLatency).arg(status.networkLatency, 3).arg(status.packetsLost, 3).arg(status.packetsSent, 3); - if (audio != Q_NULLPTR) { - status.rxAudioLevel = audio->getRxAmplitude(); - status.txAudioLevel = audio->getTxAmplitude(); - } emit haveNetworkStatus(status); } @@ -289,6 +298,8 @@ void udpHandler::dataReceived() QObject::connect(audio, SIGNAL(haveAudioData(audioPacket)), this, SLOT(receiveAudioData(audioPacket))); QObject::connect(this, SIGNAL(haveChangeLatency(quint16)), audio, SLOT(changeLatency(quint16))); QObject::connect(this, SIGNAL(haveSetVolume(unsigned char)), audio, SLOT(setVolume(unsigned char))); + QObject::connect(audio, SIGNAL(haveRxLevels(quint16, quint16, quint16,bool)), this, SLOT(getRxLevels(quint16, quint16,quint16,bool))); + QObject::connect(audio, SIGNAL(haveTxLevels(quint16, quint16,quint16,bool)), this, SLOT(getTxLevels(quint16, quint16,quint16,bool))); streamOpened = true; } @@ -810,6 +821,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint connect(this, SIGNAL(haveAudioData(audioPacket)), rxaudio, SLOT(incomingAudio(audioPacket))); connect(this, SIGNAL(haveChangeLatency(quint16)), rxaudio, SLOT(changeLatency(quint16))); connect(this, SIGNAL(haveSetVolume(unsigned char)), rxaudio, SLOT(setVolume(unsigned char))); + connect(rxaudio, SIGNAL(haveLevels(quint16, quint16, quint16,bool)), this, SLOT(getRxLevels(quint16, quint16, quint16,bool))); connect(rxAudioThread, SIGNAL(finished()), rxaudio, SLOT(deleteLater())); txSetup.format.setChannelCount(1); // TX Audio is always single channel. @@ -822,6 +834,7 @@ udpAudio::udpAudio(QHostAddress local, QHostAddress ip, quint16 audioPort, quint txAudioThread->start(QThread::TimeCriticalPriority); connect(this, SIGNAL(setupTxAudio(audioSetup)), txaudio, SLOT(init(audioSetup))); + connect(txaudio, SIGNAL(haveLevels(quint16, quint16, quint16, bool)), this, SLOT(getTxLevels(quint16, quint16, quint16, bool))); connect(txAudioThread, SIGNAL(finished()), txaudio, SLOT(deleteLater())); @@ -973,22 +986,13 @@ void udpAudio::setVolume(unsigned char value) emit haveSetVolume(value); } -quint16 udpAudio::getRxAmplitude() { - if (rxaudio != Q_NULLPTR) { - return rxaudio->getAmplitude(); - } - else { - return 0; - } +void udpAudio::getRxLevels(quint16 amplitude,quint16 latency, quint16 current, bool under) { + + emit haveRxLevels(amplitude,latency, current, under); } -quint16 udpAudio::getTxAmplitude() { - if (txaudio != Q_NULLPTR) { - return txaudio->getAmplitude(); - } - else { - return 0; - } +void udpAudio::getTxLevels(quint16 amplitude,quint16 latency, quint16 current, bool under) { + emit haveTxLevels(amplitude,latency, current, under); } void udpAudio::dataReceived() @@ -1040,7 +1044,6 @@ void udpAudio::dataReceived() // Need to do more testing but latency appears fine. //rxaudio->incomingAudio(tempAudio); emit haveAudioData(tempAudio); - audioLatency = rxaudio->getLatency(); } break; } diff --git a/udphandler.h b/udphandler.h index ca3aa2a..30757d3 100644 --- a/udphandler.h +++ b/udphandler.h @@ -43,6 +43,10 @@ struct networkStatus { quint8 txAudioLevel; quint16 rxLatency; quint16 txLatency; + bool rxUnderrun; + bool txUnderrun; + quint16 rxCurrentLatency; + quint16 txCurrentLatency; quint32 packetsSent=0; quint32 packetsLost=0; quint16 rtt=0; @@ -175,8 +179,6 @@ public: ~udpAudio(); int audioLatency = 0; - quint16 getRxAmplitude(); - quint16 getTxAmplitude(); signals: void haveAudioData(audioPacket data); @@ -186,10 +188,14 @@ signals: void haveChangeLatency(quint16 value); void haveSetVolume(unsigned char value); + void haveRxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); + void haveTxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); public slots: void changeLatency(quint16 value); void setVolume(unsigned char value); + void getRxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); + void getTxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); private: @@ -239,6 +245,8 @@ public slots: void setVolume(unsigned char value); void init(); void setCurrentRadio(quint8 radio); + void getRxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); + void getTxLevels(quint16 amplitude, quint16 latency, quint16 current, bool under); signals: